Update app.py
Browse files
app.py
CHANGED
@@ -25,11 +25,11 @@ SPECIAL_WORDS = [
|
|
25 |
]
|
26 |
|
27 |
# Global variables
|
28 |
-
|
29 |
selected_words = []
|
30 |
|
31 |
-
def generate_word_design(word, word_id
|
32 |
-
"""Generate styled design for a word."""
|
33 |
fonts = [
|
34 |
"'VT323', monospace",
|
35 |
"'Josefin Sans', sans-serif",
|
@@ -47,94 +47,75 @@ def generate_word_design(word, word_id, use_color=False):
|
|
47 |
"'Pacifico', cursive",
|
48 |
"'Teko', sans-serif"
|
49 |
]
|
50 |
-
font_sizes = ["18px", "19px", "20px"]
|
51 |
-
font_tops = ["0px", "1px", "-1px"]
|
52 |
-
letter_spacings = ["-1px", "0px", "1px"
|
53 |
text_shadows = [
|
54 |
-
"0px 0px 1px",
|
55 |
-
"0px 0px 2px",
|
56 |
-
"1px 0px 0px",
|
57 |
-
"0px 0px 0px",
|
58 |
-
"0px 1px 0px",
|
59 |
-
"0px 2px 0px",
|
60 |
-
"0px 1px 1px",
|
61 |
-
"1px 1px 0px",
|
62 |
-
"1px 0px 1px"
|
63 |
-
] if not use_color else [
|
64 |
-
"0px 0px 5px",
|
65 |
-
"2px 2px 4px",
|
66 |
-
"0px 0px 8px",
|
67 |
-
"3px 3px 6px",
|
68 |
-
"1px 1px 10px"
|
69 |
]
|
70 |
-
skew_angles = ["-25deg", "-20deg", "-15deg", "-10deg", "0deg", "10deg", "15deg", "20deg", "25deg"]
|
71 |
-
|
72 |
-
# Choose color
|
73 |
-
color = '#000000' if not use_color else f'#{random.randint(0, 0xFFFFFF):06x}'
|
74 |
-
|
75 |
-
# Generate unique animation name for movement
|
76 |
-
animation_name = f"animate_{word_id}_{random.randint(0, 10000)}"
|
77 |
|
78 |
letters = list(word)
|
79 |
styled_letters = []
|
|
|
80 |
|
81 |
for i, letter in enumerate(letters):
|
82 |
-
# Generate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
style = {
|
84 |
-
'font-family':
|
85 |
'line-height': '1.6',
|
86 |
-
'font-size':
|
87 |
-
'letter-spacing':
|
88 |
-
'text-shadow':
|
89 |
-
'transform': f'skew({
|
90 |
-
'margin-top':
|
91 |
'position': 'relative',
|
92 |
-
'top':
|
93 |
-
'color':
|
94 |
'display': 'inline-block',
|
95 |
'margin': '0 1px',
|
96 |
-
'vertical-align': 'middle'
|
|
|
97 |
}
|
98 |
|
99 |
-
if use_color:
|
100 |
-
# Animation plays once and stops (no infinite)
|
101 |
-
style['animation'] = f'{animation_name} 1.2s ease-in-out forwards'
|
102 |
-
style['animation-delay'] = f'{i * 0.15}s'
|
103 |
-
|
104 |
style_str = '; '.join([f'{k}: {v}' for k, v in style.items()])
|
105 |
-
styled_letter = f'<span class="
|
106 |
styled_letters.append(styled_letter)
|
107 |
|
108 |
-
#
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
transform: scale(1) rotate(0deg) skew({random.choice(skew_angles)});
|
114 |
-
opacity: 0.7;
|
115 |
-
}}
|
116 |
-
25% {{
|
117 |
-
transform: scale(1.3) rotate({random.choice(["-15deg", "15deg", "20deg"])}deg) skew({random.choice(skew_angles)});
|
118 |
-
opacity: 1;
|
119 |
-
}}
|
120 |
-
50% {{
|
121 |
-
transform: scale(0.9) rotate({random.choice(["-10deg", "10deg", "25deg"])}deg) skew({random.choice(skew_angles)});
|
122 |
-
opacity: 1;
|
123 |
-
}}
|
124 |
-
75% {{
|
125 |
-
transform: scale(1.2) rotate({random.choice(["-5deg", "5deg", "30deg"])}deg) skew({random.choice(skew_angles)});
|
126 |
-
opacity: 1;
|
127 |
-
}}
|
128 |
-
100% {{
|
129 |
-
transform: scale(1.1) rotate(0deg) skew({random.choice(skew_angles)});
|
130 |
-
opacity: 1;
|
131 |
-
}}
|
132 |
-
}}
|
133 |
-
</style>
|
134 |
-
""" if use_color else ""
|
135 |
|
136 |
return f'''
|
137 |
-
{keyframes}
|
138 |
<span class="word-container" id="word-{word_id}" style="display: inline-block;
|
139 |
margin: 10px;
|
140 |
padding: 8px 12px;
|
@@ -150,18 +131,16 @@ def generate_word_design(word, word_id, use_color=False):
|
|
150 |
|
151 |
def generate_random_words():
|
152 |
"""Generate 5 random words with initial styling."""
|
153 |
-
global
|
154 |
|
155 |
# Reset data
|
156 |
-
|
157 |
selected_words = random.sample(SPECIAL_WORDS, 5)
|
158 |
|
159 |
styled_words = []
|
160 |
for i, word in enumerate(selected_words):
|
161 |
-
|
162 |
-
|
163 |
-
original_word_designs[i] = original_design
|
164 |
-
styled_words.append(original_design)
|
165 |
|
166 |
final_output = f"""
|
167 |
<html>
|
@@ -190,9 +169,6 @@ def generate_random_words():
|
|
190 |
font-family: "Josefin Sans", sans-serif;
|
191 |
padding: 20px;
|
192 |
}}
|
193 |
-
.styled-letter {{
|
194 |
-
transition: all 0.6s ease;
|
195 |
-
}}
|
196 |
</style>
|
197 |
</head>
|
198 |
<body>
|
@@ -209,31 +185,90 @@ def generate_random_words():
|
|
209 |
return final_output
|
210 |
|
211 |
def trigger_movement(input_html):
|
212 |
-
"""Function to
|
213 |
-
global
|
214 |
|
215 |
-
if not
|
216 |
return input_html
|
217 |
|
218 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
|
220 |
-
# Replace each word with its completely new animated version
|
221 |
-
for i, word in enumerate(selected_words):
|
222 |
-
if i in original_word_designs:
|
223 |
-
# Generate COMPLETELY NEW design with color and animation (that stops)
|
224 |
-
new_movement_design = generate_word_design(word, i, use_color=True)
|
225 |
-
# Replace the original design with the new one
|
226 |
-
updated_html = updated_html.replace(original_word_designs[i], new_movement_design, 1)
|
227 |
-
|
228 |
return updated_html
|
229 |
|
230 |
# Create Gradio interface using Blocks
|
231 |
with gr.Blocks() as demo:
|
232 |
-
gr.Markdown("# Random Word Styler\
|
233 |
|
234 |
generate_button = gr.Button("Generate Random Words", variant="primary")
|
235 |
output_html = gr.HTML()
|
236 |
-
animate_button = gr.Button("Trigger Movement
|
237 |
|
238 |
generate_button.click(generate_random_words, outputs=output_html)
|
239 |
animate_button.click(trigger_movement, inputs=output_html, outputs=output_html)
|
|
|
25 |
]
|
26 |
|
27 |
# Global variables
|
28 |
+
original_word_styles = {}
|
29 |
selected_words = []
|
30 |
|
31 |
+
def generate_word_design(word, word_id):
|
32 |
+
"""Generate initial styled design for a word (black color)."""
|
33 |
fonts = [
|
34 |
"'VT323', monospace",
|
35 |
"'Josefin Sans', sans-serif",
|
|
|
47 |
"'Pacifico', cursive",
|
48 |
"'Teko', sans-serif"
|
49 |
]
|
50 |
+
font_sizes = ["18px", "19px", "20px"]
|
51 |
+
font_tops = ["0px", "1px", "-1px"]
|
52 |
+
letter_spacings = ["-1px", "0px", "1px", "2px"]
|
53 |
text_shadows = [
|
54 |
+
"0px 0px 1px #000",
|
55 |
+
"0px 0px 2px #000",
|
56 |
+
"1px 0px 0px #000",
|
57 |
+
"0px 0px 0px #000",
|
58 |
+
"0px 1px 0px #000",
|
59 |
+
"0px 2px 0px #000",
|
60 |
+
"0px 1px 1px #000",
|
61 |
+
"1px 1px 0px #000",
|
62 |
+
"1px 0px 1px #000"
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
]
|
64 |
+
skew_angles = ["-25deg", "-20deg", "-15deg", "-10deg", "0deg", "10deg", "15deg", "20deg", "25deg"]
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
|
66 |
letters = list(word)
|
67 |
styled_letters = []
|
68 |
+
letter_styles_data = []
|
69 |
|
70 |
for i, letter in enumerate(letters):
|
71 |
+
# Generate and store original styles
|
72 |
+
font_family = random.choice(fonts)
|
73 |
+
font_size = random.choice(font_sizes)
|
74 |
+
letter_spacing = random.choice(letter_spacings)
|
75 |
+
text_shadow = random.choice(text_shadows)
|
76 |
+
skew_angle = random.choice(skew_angles)
|
77 |
+
margin_top = random.choice(["-0.02cm", "0.00cm", "0.02cm"])
|
78 |
+
top = random.choice(font_tops)
|
79 |
+
|
80 |
+
# Store original styles for transition
|
81 |
+
letter_styles_data.append({
|
82 |
+
'font_family': font_family,
|
83 |
+
'font_size': font_size,
|
84 |
+
'letter_spacing': letter_spacing,
|
85 |
+
'text_shadow': text_shadow,
|
86 |
+
'skew_angle': skew_angle,
|
87 |
+
'margin_top': margin_top,
|
88 |
+
'top': top
|
89 |
+
})
|
90 |
+
|
91 |
style = {
|
92 |
+
'font-family': font_family,
|
93 |
'line-height': '1.6',
|
94 |
+
'font-size': font_size,
|
95 |
+
'letter-spacing': letter_spacing,
|
96 |
+
'text-shadow': text_shadow,
|
97 |
+
'transform': f'skew({skew_angle})',
|
98 |
+
'margin-top': margin_top,
|
99 |
'position': 'relative',
|
100 |
+
'top': top,
|
101 |
+
'color': '#000000',
|
102 |
'display': 'inline-block',
|
103 |
'margin': '0 1px',
|
104 |
+
'vertical-align': 'middle',
|
105 |
+
'transition': 'all 0.8s ease-in-out' # Smooth transition for all properties
|
106 |
}
|
107 |
|
|
|
|
|
|
|
|
|
|
|
108 |
style_str = '; '.join([f'{k}: {v}' for k, v in style.items()])
|
109 |
+
styled_letter = f'<span class="letter-{word_id}-{i}" style="{style_str}">{letter}</span>'
|
110 |
styled_letters.append(styled_letter)
|
111 |
|
112 |
+
# Store styles for animation
|
113 |
+
original_word_styles[word_id] = {
|
114 |
+
'word': word,
|
115 |
+
'letter_styles': letter_styles_data
|
116 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
|
118 |
return f'''
|
|
|
119 |
<span class="word-container" id="word-{word_id}" style="display: inline-block;
|
120 |
margin: 10px;
|
121 |
padding: 8px 12px;
|
|
|
131 |
|
132 |
def generate_random_words():
|
133 |
"""Generate 5 random words with initial styling."""
|
134 |
+
global original_word_styles, selected_words
|
135 |
|
136 |
# Reset data
|
137 |
+
original_word_styles = {}
|
138 |
selected_words = random.sample(SPECIAL_WORDS, 5)
|
139 |
|
140 |
styled_words = []
|
141 |
for i, word in enumerate(selected_words):
|
142 |
+
word_design = generate_word_design(word, i)
|
143 |
+
styled_words.append(word_design)
|
|
|
|
|
144 |
|
145 |
final_output = f"""
|
146 |
<html>
|
|
|
169 |
font-family: "Josefin Sans", sans-serif;
|
170 |
padding: 20px;
|
171 |
}}
|
|
|
|
|
|
|
172 |
</style>
|
173 |
</head>
|
174 |
<body>
|
|
|
185 |
return final_output
|
186 |
|
187 |
def trigger_movement(input_html):
|
188 |
+
"""Function to create smooth transitions from original values to new values."""
|
189 |
+
global original_word_styles, selected_words
|
190 |
|
191 |
+
if not original_word_styles or not selected_words:
|
192 |
return input_html
|
193 |
|
194 |
+
# Generate new target styles for transition
|
195 |
+
fonts = [
|
196 |
+
"'VT323', monospace", "'Josefin Sans', sans-serif", "'Rajdhani', sans-serif", "'Anton', sans-serif",
|
197 |
+
"'Caveat', cursive", "'Patrick Hand', cursive", "'Nothing You Could Do', cursive", "'Reenie Beanie', cursive",
|
198 |
+
"'Orbitron', sans-serif", "'Raleway', sans-serif", "'Open Sans Condensed', sans-serif", "'Poiret One', cursive",
|
199 |
+
"'Indie Flower', cursive", "'Pacifico', cursive", "'Teko', sans-serif"
|
200 |
+
]
|
201 |
+
|
202 |
+
# Create JavaScript for smooth transitions
|
203 |
+
animation_script = """
|
204 |
+
<script>
|
205 |
+
function triggerSmoothTransitions() {
|
206 |
+
"""
|
207 |
+
|
208 |
+
for word_id, data in original_word_styles.items():
|
209 |
+
word = data['word']
|
210 |
+
letter_styles = data['letter_styles']
|
211 |
+
|
212 |
+
for i, original_style in enumerate(letter_styles):
|
213 |
+
# Generate NEW target values
|
214 |
+
new_color = f"#{random.randint(0, 0xFFFFFF):06x}"
|
215 |
+
new_font_family = random.choice(fonts)
|
216 |
+
new_font_size = random.choice(["20px", "22px", "24px", "26px"])
|
217 |
+
new_letter_spacing = random.choice(["-3px", "-2px", "0px", "2px", "3px", "4px"])
|
218 |
+
new_text_shadow = random.choice([
|
219 |
+
f"0px 0px 5px {new_color}",
|
220 |
+
f"2px 2px 4px {new_color}",
|
221 |
+
f"0px 0px 8px {new_color}",
|
222 |
+
f"3px 3px 6px {new_color}",
|
223 |
+
"none"
|
224 |
+
])
|
225 |
+
new_skew = random.choice(["-35deg", "-25deg", "0deg", "25deg", "35deg", "45deg"])
|
226 |
+
new_top = random.choice(["-3px", "0px", "3px", "5px"])
|
227 |
+
new_margin_top = random.choice(["-0.05cm", "0.00cm", "0.03cm", "0.05cm"])
|
228 |
+
|
229 |
+
animation_script += f"""
|
230 |
+
// Animate letter {i} of word {word_id}
|
231 |
+
setTimeout(() => {{
|
232 |
+
const letter = document.querySelector('.letter-{word_id}-{i}');
|
233 |
+
if (letter) {{
|
234 |
+
// Font changes instantly (can't interpolate)
|
235 |
+
letter.style.fontFamily = '{new_font_family}';
|
236 |
+
|
237 |
+
// These properties transition smoothly from original to new values
|
238 |
+
letter.style.color = '{new_color}';
|
239 |
+
letter.style.fontSize = '{new_font_size}';
|
240 |
+
letter.style.letterSpacing = '{new_letter_spacing}';
|
241 |
+
letter.style.textShadow = '{new_text_shadow}';
|
242 |
+
letter.style.transform = 'skew({new_skew}) scale(1.1)';
|
243 |
+
letter.style.top = '{new_top}';
|
244 |
+
letter.style.marginTop = '{new_margin_top}';
|
245 |
+
}}
|
246 |
+
}}, {i * 100});
|
247 |
+
"""
|
248 |
+
|
249 |
+
animation_script += """
|
250 |
+
}
|
251 |
+
|
252 |
+
// Trigger the transitions
|
253 |
+
triggerSmoothTransitions();
|
254 |
+
</script>
|
255 |
+
"""
|
256 |
+
|
257 |
+
# Add the script to the HTML
|
258 |
+
if "</body>" in input_html:
|
259 |
+
updated_html = input_html.replace("</body>", animation_script + "</body>")
|
260 |
+
else:
|
261 |
+
updated_html = input_html + animation_script
|
262 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
return updated_html
|
264 |
|
265 |
# Create Gradio interface using Blocks
|
266 |
with gr.Blocks() as demo:
|
267 |
+
gr.Markdown("# Random Word Styler\nWords smoothly transition from their original styling to completely new styling!")
|
268 |
|
269 |
generate_button = gr.Button("Generate Random Words", variant="primary")
|
270 |
output_html = gr.HTML()
|
271 |
+
animate_button = gr.Button("Trigger Smooth Movement", variant="secondary")
|
272 |
|
273 |
generate_button.click(generate_random_words, outputs=output_html)
|
274 |
animate_button.click(trigger_movement, inputs=output_html, outputs=output_html)
|