first commit
Browse files- app.py +85 -0
- requirements.txt +2 -0
- static/styles.css +276 -0
- templates/index.html +97 -0
app.py
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from flask import Flask, render_template, request, send_file
|
2 |
+
from google import genai
|
3 |
+
from google.genai import types
|
4 |
+
import base64
|
5 |
+
import os
|
6 |
+
import io
|
7 |
+
import unicodedata
|
8 |
+
app = Flask(__name__)
|
9 |
+
|
10 |
+
genai.Client(api_key=os.environ["GOOGLE_API_KEY"])
|
11 |
+
|
12 |
+
def emoji_to_text(emoji):
|
13 |
+
try:
|
14 |
+
return unicodedata.name(emoji)
|
15 |
+
except ValueError:
|
16 |
+
return ""
|
17 |
+
|
18 |
+
def is_emoji(text):
|
19 |
+
import re
|
20 |
+
emoji_pattern = re.compile(
|
21 |
+
"["
|
22 |
+
"\U0001F000-\U0001F9FF"
|
23 |
+
"\U0001F300-\U0001F5FF"
|
24 |
+
"\U00002702-\U000027B0"
|
25 |
+
"\U000024C2-\U0001F251"
|
26 |
+
"]+", flags=re.UNICODE)
|
27 |
+
|
28 |
+
return bool(emoji_pattern.fullmatch(text))
|
29 |
+
|
30 |
+
|
31 |
+
def generate_creepy_emoji(emoji):
|
32 |
+
description = emoji_to_text(emoji)
|
33 |
+
client = genai.Client()
|
34 |
+
response = client.models.generate_content(
|
35 |
+
model="gemini-2.0-flash-exp-image-generation",
|
36 |
+
contents=(
|
37 |
+
f"""
|
38 |
+
Generate a hyper-realistic and highly detailed image of the {emoji} emoji. This image should depict a **realistic, textured**, and **wrinkled** version of the {description} emoji, transforming it into an unsettling and eerie representation.
|
39 |
+
If it is not a face emoji, add a face to the image. If it is a cat face emoji, make sure you include the cat aspects in the emoji
|
40 |
+
Plan out what you are going to generate before, make sure you understand what the emoji contains in itself.
|
41 |
+
Make sure you generate the image as well as the prompt
|
42 |
+
|
43 |
+
- **Facial Features**: The skin should appear aged, with deep wrinkles, pores, and imperfections, making it look as lifelike as possible.
|
44 |
+
- **Texture & Detail**: The skin should have a hyper-detailed texture, including fine lines, blemishes, and realistic lighting effects to enhance the **creepy and unsettling** aesthetic.
|
45 |
+
- **Color & Lighting**: Use **appropriate colors** (typically yellow for facial emojis), ensuring **shadows and highlights** enhance realism. The lighting should create an eerie atmosphere, possibly with unnatural or dim lighting to increase the unsettling effect.
|
46 |
+
- **Mood & Style**: The image should evoke a sense of unease, making the emoji appear unnervingly lifelike, almost **uncanny valley** in effect.
|
47 |
+
- **Follow Emoji**: Make sure that you follow all elements that should be in the emoji, like tears, laughing tears of joy, and other liquids, as well as other things. For example the smirking emoji should be smirking, not deadpan. The laughing emoji should have tears of joy, ect...
|
48 |
+
"""
|
49 |
+
),
|
50 |
+
config=types.GenerateContentConfig(
|
51 |
+
response_modalities=[
|
52 |
+
"image",
|
53 |
+
"text",
|
54 |
+
],
|
55 |
+
),
|
56 |
+
)
|
57 |
+
|
58 |
+
if response and response.candidates:
|
59 |
+
for candidate in response.candidates:
|
60 |
+
if candidate.content and candidate.content.parts:
|
61 |
+
for part in candidate.content.parts:
|
62 |
+
if hasattr(part, "inline_data") and part.inline_data:
|
63 |
+
return part.inline_data.data
|
64 |
+
return None
|
65 |
+
|
66 |
+
@app.route("/", methods=["GET", "POST"])
|
67 |
+
def index():
|
68 |
+
return render_template("index.html")
|
69 |
+
|
70 |
+
@app.route("/generate", methods=["POST"])
|
71 |
+
def generate():
|
72 |
+
emoji = request.form["emoji"]
|
73 |
+
if not is_emoji(emoji):
|
74 |
+
return {"error": "Please enter only emoji characters."}, 400
|
75 |
+
|
76 |
+
image_data = generate_creepy_emoji(emoji)
|
77 |
+
if image_data:
|
78 |
+
encoded_image = base64.b64encode(image_data).decode('utf-8')
|
79 |
+
return {"image": f"data:image/png;base64,{encoded_image}"}
|
80 |
+
else:
|
81 |
+
return {"error": "No image generated."}, 400
|
82 |
+
|
83 |
+
|
84 |
+
if __name__ == "__main__":
|
85 |
+
app.run(host="0.0.0.0", port=7860)
|
requirements.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
flask
|
2 |
+
google-generativeai
|
static/styles.css
ADDED
@@ -0,0 +1,276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* Refined Dark Midnight Blue Theme with Elegant Magical Accents */
|
2 |
+
:root {
|
3 |
+
--midnight-blue: #0a0a1a;
|
4 |
+
--deep-blue: #131330;
|
5 |
+
--accent-purple: #9d4edd;
|
6 |
+
--accent-blue: #3a86ff;
|
7 |
+
--glow-purple: rgba(157, 78, 221, 0.3);
|
8 |
+
--glow-blue: rgba(58, 134, 255, 0.3);
|
9 |
+
--text-color: #e6e6ff;
|
10 |
+
--star-color: rgba(255, 255, 255, 0.4);
|
11 |
+
--container-bg: rgba(19, 19, 48, 0.85);
|
12 |
+
}
|
13 |
+
|
14 |
+
body {
|
15 |
+
background-color: var(--midnight-blue);
|
16 |
+
color: var(--text-color);
|
17 |
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
18 |
+
margin: 0;
|
19 |
+
padding: 0;
|
20 |
+
min-height: 100vh;
|
21 |
+
background-image:
|
22 |
+
radial-gradient(var(--star-color) 1px, transparent 1px);
|
23 |
+
background-size: 80px 80px;
|
24 |
+
background-position: 0 0;
|
25 |
+
background-attachment: fixed;
|
26 |
+
display: flex;
|
27 |
+
flex-direction: column;
|
28 |
+
align-items: center;
|
29 |
+
justify-content: center;
|
30 |
+
}
|
31 |
+
|
32 |
+
.container {
|
33 |
+
background-color: var(--container-bg);
|
34 |
+
backdrop-filter: blur(10px);
|
35 |
+
border-radius: 20px;
|
36 |
+
padding: 2.5rem;
|
37 |
+
max-width: 500px;
|
38 |
+
width: 90%;
|
39 |
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3),
|
40 |
+
0 0 15px var(--glow-purple);
|
41 |
+
position: relative;
|
42 |
+
overflow: hidden;
|
43 |
+
border: 1px solid rgba(157, 78, 221, 0.1);
|
44 |
+
}
|
45 |
+
|
46 |
+
.container::after {
|
47 |
+
content: '';
|
48 |
+
position: absolute;
|
49 |
+
top: 0;
|
50 |
+
left: 0;
|
51 |
+
right: 0;
|
52 |
+
height: 1px;
|
53 |
+
background: linear-gradient(90deg,
|
54 |
+
transparent,
|
55 |
+
var(--accent-purple),
|
56 |
+
var(--accent-blue),
|
57 |
+
transparent
|
58 |
+
);
|
59 |
+
}
|
60 |
+
|
61 |
+
h1 {
|
62 |
+
color: var(--text-color);
|
63 |
+
text-align: center;
|
64 |
+
margin-bottom: 2rem;
|
65 |
+
font-size: 2.8rem;
|
66 |
+
letter-spacing: 2px;
|
67 |
+
font-weight: 700;
|
68 |
+
background: linear-gradient(120deg, #e6e6ff, var(--accent-purple), var(--accent-blue), #e6e6ff);
|
69 |
+
-webkit-background-clip: text;
|
70 |
+
-webkit-text-fill-color: transparent;
|
71 |
+
background-size: 300% 100%;
|
72 |
+
animation: gradient-shift 8s ease infinite;
|
73 |
+
position: relative;
|
74 |
+
}
|
75 |
+
|
76 |
+
@keyframes gradient-shift {
|
77 |
+
0%, 100% { background-position: 0% 50%; }
|
78 |
+
50% { background-position: 100% 50%; }
|
79 |
+
}
|
80 |
+
|
81 |
+
form {
|
82 |
+
position: relative;
|
83 |
+
z-index: 1;
|
84 |
+
}
|
85 |
+
|
86 |
+
label {
|
87 |
+
display: block;
|
88 |
+
margin-bottom: 0.8rem;
|
89 |
+
font-size: 1.1rem;
|
90 |
+
color: var(--accent-purple);
|
91 |
+
letter-spacing: 0.5px;
|
92 |
+
font-weight: 500;
|
93 |
+
opacity: 0.9;
|
94 |
+
}
|
95 |
+
|
96 |
+
input[type="text"] {
|
97 |
+
width: 100%;
|
98 |
+
padding: 0.9rem;
|
99 |
+
border: 2px solid rgba(58, 134, 255, 0.2);
|
100 |
+
border-radius: 12px;
|
101 |
+
background-color: rgba(10, 10, 26, 0.5);
|
102 |
+
color: var(--text-color);
|
103 |
+
font-size: 2rem;
|
104 |
+
box-sizing: border-box;
|
105 |
+
transition: all 0.25s ease;
|
106 |
+
text-align: center;
|
107 |
+
margin-bottom: 1.2rem;
|
108 |
+
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.1);
|
109 |
+
}
|
110 |
+
|
111 |
+
input[type="text"]:focus {
|
112 |
+
outline: none;
|
113 |
+
border-color: var(--accent-purple);
|
114 |
+
box-shadow: 0 0 0 3px var(--glow-purple),
|
115 |
+
inset 0 2px 5px rgba(0, 0, 0, 0.1);
|
116 |
+
}
|
117 |
+
|
118 |
+
button {
|
119 |
+
display: block;
|
120 |
+
width: 100%;
|
121 |
+
padding: 0.9rem;
|
122 |
+
background: linear-gradient(135deg,
|
123 |
+
rgba(58, 134, 255, 0.9),
|
124 |
+
rgba(157, 78, 221, 0.9)
|
125 |
+
);
|
126 |
+
border: none;
|
127 |
+
border-radius: 12px;
|
128 |
+
color: white;
|
129 |
+
font-size: 1.1rem;
|
130 |
+
font-weight: 600;
|
131 |
+
letter-spacing: 0.5px;
|
132 |
+
cursor: pointer;
|
133 |
+
transition: all 0.3s ease;
|
134 |
+
position: relative;
|
135 |
+
overflow: hidden;
|
136 |
+
box-shadow: 0 4px 12px rgba(157, 78, 221, 0.3);
|
137 |
+
}
|
138 |
+
|
139 |
+
button::after {
|
140 |
+
content: '';
|
141 |
+
position: absolute;
|
142 |
+
top: 0;
|
143 |
+
left: 0;
|
144 |
+
width: 100%;
|
145 |
+
height: 100%;
|
146 |
+
background: linear-gradient(90deg,
|
147 |
+
transparent,
|
148 |
+
rgba(255, 255, 255, 0.1),
|
149 |
+
transparent
|
150 |
+
);
|
151 |
+
transform: translateX(-100%);
|
152 |
+
transition: transform 0.6s ease;
|
153 |
+
}
|
154 |
+
|
155 |
+
button:hover::after {
|
156 |
+
transform: translateX(100%);
|
157 |
+
}
|
158 |
+
|
159 |
+
button:hover {
|
160 |
+
transform: translateY(-2px);
|
161 |
+
box-shadow: 0 6px 15px rgba(157, 78, 221, 0.4);
|
162 |
+
}
|
163 |
+
|
164 |
+
button:active {
|
165 |
+
transform: translateY(1px);
|
166 |
+
}
|
167 |
+
|
168 |
+
#result-container {
|
169 |
+
margin-top: 2.5rem;
|
170 |
+
min-height: 200px;
|
171 |
+
display: flex;
|
172 |
+
flex-direction: column;
|
173 |
+
align-items: center;
|
174 |
+
justify-content: center;
|
175 |
+
position: relative;
|
176 |
+
z-index: 1;
|
177 |
+
}
|
178 |
+
|
179 |
+
#loading {
|
180 |
+
display: none;
|
181 |
+
text-align: center;
|
182 |
+
width: 100%;
|
183 |
+
}
|
184 |
+
|
185 |
+
.loading-bar {
|
186 |
+
height: 4px;
|
187 |
+
width: 100%;
|
188 |
+
position: relative;
|
189 |
+
overflow: hidden;
|
190 |
+
background-color: rgba(157, 78, 221, 0.2);
|
191 |
+
border-radius: 2px;
|
192 |
+
margin: 1.5rem 0;
|
193 |
+
}
|
194 |
+
|
195 |
+
.loading-bar::before {
|
196 |
+
content: "";
|
197 |
+
position: absolute;
|
198 |
+
left: -50%;
|
199 |
+
height: 100%;
|
200 |
+
width: 50%;
|
201 |
+
background: linear-gradient(90deg,
|
202 |
+
transparent,
|
203 |
+
var(--accent-purple),
|
204 |
+
var(--accent-blue)
|
205 |
+
);
|
206 |
+
animation: loading 1.5s infinite ease;
|
207 |
+
border-radius: 2px;
|
208 |
+
}
|
209 |
+
|
210 |
+
@keyframes loading {
|
211 |
+
0% {
|
212 |
+
left: -50%;
|
213 |
+
}
|
214 |
+
100% {
|
215 |
+
left: 100%;
|
216 |
+
}
|
217 |
+
}
|
218 |
+
|
219 |
+
.loading-text {
|
220 |
+
font-size: 1rem;
|
221 |
+
letter-spacing: 0.5px;
|
222 |
+
color: rgba(230, 230, 255, 0.8);
|
223 |
+
margin-bottom: 0.5rem;
|
224 |
+
}
|
225 |
+
|
226 |
+
.emoji-result {
|
227 |
+
max-width: 100%;
|
228 |
+
border-radius: 15px;
|
229 |
+
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3),
|
230 |
+
0 0 20px var(--glow-blue);
|
231 |
+
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
232 |
+
}
|
233 |
+
|
234 |
+
.emoji-result:hover {
|
235 |
+
transform: scale(1.03);
|
236 |
+
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.4),
|
237 |
+
0 0 25px var(--glow-purple);
|
238 |
+
}
|
239 |
+
|
240 |
+
.error-message {
|
241 |
+
color: #ff6b8b;
|
242 |
+
text-align: center;
|
243 |
+
font-size: 1rem;
|
244 |
+
background-color: rgba(255, 107, 139, 0.08);
|
245 |
+
padding: 0.9rem 1.2rem;
|
246 |
+
border-radius: 10px;
|
247 |
+
border-left: 3px solid rgba(255, 107, 139, 0.5);
|
248 |
+
margin-top: 0.5rem;
|
249 |
+
}
|
250 |
+
|
251 |
+
/* Subtle pulsing glow on container */
|
252 |
+
@keyframes subtle-pulse {
|
253 |
+
0%, 100% {
|
254 |
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3),
|
255 |
+
0 0 15px var(--glow-purple);
|
256 |
+
}
|
257 |
+
50% {
|
258 |
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3),
|
259 |
+
0 0 20px var(--glow-blue);
|
260 |
+
}
|
261 |
+
}
|
262 |
+
|
263 |
+
.container {
|
264 |
+
animation: subtle-pulse 8s infinite ease-in-out;
|
265 |
+
}
|
266 |
+
|
267 |
+
/* Responsive adjustments */
|
268 |
+
@media (max-width: 500px) {
|
269 |
+
.container {
|
270 |
+
padding: 2rem;
|
271 |
+
}
|
272 |
+
|
273 |
+
h1 {
|
274 |
+
font-size: 2.2rem;
|
275 |
+
}
|
276 |
+
}
|
templates/index.html
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html>
|
3 |
+
<head>
|
4 |
+
<title>Creepmoji</title>
|
5 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7 |
+
</head>
|
8 |
+
<body>
|
9 |
+
<div class="container">
|
10 |
+
<h1>Creepmoji</h1>
|
11 |
+
<form id="emoji-form">
|
12 |
+
<label for="emoji">Enter Emoji:</label>
|
13 |
+
<input type="text" id="emoji" name="emoji" maxlength="2" placeholder="😀" autocomplete="off">
|
14 |
+
<button type="submit">Generate Creepmoji</button>
|
15 |
+
</form>
|
16 |
+
|
17 |
+
<div id="result-container">
|
18 |
+
<div id="loading">
|
19 |
+
<div class="loading-text">Creating your masterpiece...</div>
|
20 |
+
<div class="loading-bar"></div>
|
21 |
+
</div>
|
22 |
+
<div id="emoji-display"></div>
|
23 |
+
</div>
|
24 |
+
</div>
|
25 |
+
|
26 |
+
<script>
|
27 |
+
// Client-side emoji validation
|
28 |
+
document.getElementById('emoji').addEventListener('input', function(e) {
|
29 |
+
let value = e.target.value;
|
30 |
+
// Keep only emoji characters
|
31 |
+
const emojiRegex = /[\p{Emoji}]/gu;
|
32 |
+
const emojis = value.match(emojiRegex);
|
33 |
+
|
34 |
+
if (emojis) {
|
35 |
+
e.target.value = emojis.join('');
|
36 |
+
} else {
|
37 |
+
e.target.value = '';
|
38 |
+
}
|
39 |
+
|
40 |
+
// Limit to a single emoji
|
41 |
+
if (e.target.value.length > 2) {
|
42 |
+
e.target.value = e.target.value.slice(0, 2);
|
43 |
+
}
|
44 |
+
});
|
45 |
+
|
46 |
+
document.getElementById('emoji-form').addEventListener('submit', function(e) {
|
47 |
+
e.preventDefault();
|
48 |
+
|
49 |
+
const emoji = document.getElementById('emoji').value.trim();
|
50 |
+
if (!emoji) {
|
51 |
+
document.getElementById('emoji-display').innerHTML = '<div class="error-message">Please enter an emoji.</div>';
|
52 |
+
return;
|
53 |
+
}
|
54 |
+
|
55 |
+
// Show loading indicator
|
56 |
+
document.getElementById('loading').style.display = 'block';
|
57 |
+
document.getElementById('emoji-display').innerHTML = '';
|
58 |
+
|
59 |
+
// Get form data
|
60 |
+
const formData = new FormData(this);
|
61 |
+
|
62 |
+
// Send AJAX request
|
63 |
+
fetch('/generate', {
|
64 |
+
method: 'POST',
|
65 |
+
body: formData
|
66 |
+
})
|
67 |
+
.then(response => response.json())
|
68 |
+
.then(data => {
|
69 |
+
// Hide loading indicator
|
70 |
+
document.getElementById('loading').style.display = 'none';
|
71 |
+
|
72 |
+
if (data.error) {
|
73 |
+
document.getElementById('emoji-display').innerHTML = `<div class="error-message">${data.error}</div>`;
|
74 |
+
} else {
|
75 |
+
// Display the image with a fade-in effect
|
76 |
+
const img = document.createElement('img');
|
77 |
+
img.src = data.image;
|
78 |
+
img.className = 'emoji-result';
|
79 |
+
img.alt = 'Creepy Emoji';
|
80 |
+
img.style.opacity = '0';
|
81 |
+
document.getElementById('emoji-display').appendChild(img);
|
82 |
+
|
83 |
+
// Trigger fade-in effect
|
84 |
+
setTimeout(() => {
|
85 |
+
img.style.transition = 'opacity 0.6s ease';
|
86 |
+
img.style.opacity = '1';
|
87 |
+
}, 50);
|
88 |
+
}
|
89 |
+
})
|
90 |
+
.catch(error => {
|
91 |
+
document.getElementById('loading').style.display = 'none';
|
92 |
+
document.getElementById('emoji-display').innerHTML = `<div class="error-message">Error: ${error}</div>`;
|
93 |
+
});
|
94 |
+
});
|
95 |
+
</script>
|
96 |
+
</body>
|
97 |
+
</html>
|