circulartext's picture
Update app.py
dfee116 verified
import gradio as gr
import random
# Your predefined words list
SPECIAL_WORDS = [
'pikachu', 'charizard', 'bulbasaur', 'squirtle', 'mewtwo', 'mew', 'eevee', 'snorlax', 'jigglypuff', 'gengar',
'alakazam', 'machamp', 'dragonite', 'gyarados', 'lapras', 'articuno', 'zapdos', 'moltres', 'ditto', 'vaporeon',
'jolteon', 'flareon', 'umbreon', 'espeon', 'lucario', 'garchomp', 'greninja', 'rayquaza', 'kyogre', 'groudon',
'dialga', 'palkia', 'giratina', 'arceus', 'reshiram', 'zekrom', 'kyurem', 'xerneas', 'yveltal', 'zygarde',
'solgaleo', 'lunala', 'necrozma', 'zacian', 'zamazenta', 'eternatus', 'koraidon', 'miraidon', 'meowth', 'psyduck',
'pokemon', 'trainer', 'evolution', 'pokeball', 'great', 'ultra', 'master', 'pokedex', 'gym', 'leader',
'champion', 'elite', 'four', 'professor', 'oak', 'ash', 'ketchum', 'misty', 'brock', 'team',
'rocket', 'jessie', 'james', 'giovanni', 'lance', 'cynthia', 'red', 'blue', 'gary', 'battle',
'wild', 'legendary', 'mythical', 'shiny', 'mega', 'gigantamax', 'dynamax', 'type', 'fire', 'water',
'grass', 'electric', 'psychic', 'dragon', 'ghost', 'dark', 'fairy', 'fighting', 'flying', 'kanto',
'johto', 'hoenn', 'sinnoh', 'unova', 'kalos', 'alola', 'galar', 'paldea', 'region', 'pallet',
'town', 'viridian', 'city', 'cerulean', 'vermilion', 'lavender', 'celadon', 'saffron', 'fuchsia', 'cinnabar',
'island', 'indigo', 'plateau', 'victory', 'road', 'pokemon', 'center', 'mart', 'league', 'starter',
'charmander', 'rattata', 'pidgey', 'caterpie', 'weedle', 'kakuna', 'metapod', 'butterfree', 'beedrill', 'potion',
'revive', 'rare', 'candy', 'technical', 'machine', 'hidden', 'ability', 'nature', 'stats', 'attack',
'defense', 'speed', 'special', 'hp', 'experience', 'level', 'catch', 'faint', 'status', 'paralysis',
'poison', 'burn', 'freeze', 'sleep', 'confusion', 'move', 'physical', 'competitive', 'tournament', 'badge']
# Global variables
original_designs = {}
selected_words = []
def generate_word_design(word, word_id, is_animated=False):
"""Generate styled design for a word."""
fonts = [
"'VT323', monospace",
"'Josefin Sans', sans-serif",
"'Rajdhani', sans-serif",
"'Anton', sans-serif",
"'Caveat', cursive",
"'Patrick Hand', cursive",
"'Nothing You Could Do', cursive",
"'Reenie Beanie', cursive",
"'Orbitron', sans-serif",
"'Raleway', sans-serif",
"'Open Sans Condensed', sans-serif",
"'Indie Flower', cursive",
"'Pacifico', cursive",
"'Teko', sans-serif"
]
if not is_animated:
# Original state values
font_sizes = ["18px", "19px", "20px"]
font_tops = ["0px", "1px", "-1px"]
letter_spacings = ["-1px", "0px", "1px", "2px"]
text_shadows = ["0px 0px 1px #000", "0px 0px 2px #000", "1px 0px 0px #000", "0px 0px 0px #000"]
skew_angles = ["-25deg", "-20deg", "-15deg", "-10deg", "0deg", "10deg", "15deg", "20deg", "25deg"]
word_color = "#000000" # All letters in original word are black
else:
# Animated state values
font_sizes = ["18px", "19px", "20px"]
font_tops = ["0px", "1px", "-1px"]
letter_spacings = ["-1px", "0px", "1px", "2px"]
text_shadows = ["0px 0px 1px #000", "0px 0px 2px #000", "1px 0px 0px #000", "0px 0px 0px #000"]
skew_angles = ["-25deg", "-20deg", "-15deg", "-10deg", "0deg", "10deg", "15deg", "20deg", "25deg"]
word_color = f"#{random.randint(0, 0xFFFFFF):06x}" # ONE color for the entire word
letters = list(word)
styled_letters = []
keyframes_css = ""
if is_animated:
# Get original styles to create transition keyframes
original_data = original_designs.get(word_id, {})
for i, letter in enumerate(letters):
if not is_animated:
# Store original values for later animation
if word_id not in original_designs:
original_designs[word_id] = {'letters': [], 'word_color': word_color}
original_styles = {
'font_family': random.choice(fonts),
'font_size': random.choice(font_sizes),
'letter_spacing': random.choice(letter_spacings),
'text_shadow': random.choice(text_shadows),
'skew_angle': random.choice(skew_angles),
'margin_top': random.choice(["-0.02cm", "0.00cm", "0.02cm"]),
'top': random.choice(font_tops),
'color': word_color # Same color for all letters in this word
}
original_designs[word_id]['letters'].append(original_styles)
original_designs[word_id]['word_color'] = word_color
style = {
'font-family': original_styles['font_family'],
'line-height': '1.6',
'font-size': original_styles['font_size'],
'letter-spacing': original_styles['letter_spacing'],
'text-shadow': original_styles['text_shadow'],
'transform': f'skew({original_styles["skew_angle"]})',
'margin-top': original_styles['margin_top'],
'position': 'relative',
'top': original_styles['top'],
'color': original_styles['color'],
'display': 'inline-block',
'margin': '0 1px',
'vertical-align': 'middle'
}
else:
# Create animated version with keyframes
original_letter_styles = original_data['letters'][i] if i < len(original_data.get('letters', [])) else {}
original_word_color = original_data.get('word_color', '#000000')
# New target values (but same color for all letters in this word)
new_font_family = random.choice(fonts)
new_font_size = random.choice(font_sizes)
new_letter_spacing = random.choice(letter_spacings)
new_text_shadow = f"{random.choice(text_shadows)} {word_color}" # Use word_color for shadow
new_skew_angle = random.choice(skew_angles)
new_top = random.choice(font_tops)
new_margin_top = random.choice(["-0.05cm", "0.00cm", "0.03cm", "0.05cm"])
# Create unique animation name
animation_name = f"move_{word_id}_{i}_{random.randint(1000, 9999)}"
# Get original values for keyframes
orig_font_size = original_letter_styles.get('font_size', '18px')
orig_letter_spacing = original_letter_styles.get('letter_spacing', '0px')
orig_color = original_letter_styles.get('color', '#000000')
orig_text_shadow = original_letter_styles.get('text_shadow', '0px 0px 0px #000')
orig_skew_angle = original_letter_styles.get('skew_angle', '0deg')
orig_top = original_letter_styles.get('top', '0px')
orig_margin_top = original_letter_styles.get('margin_top', '0.00cm')
# Create keyframes that transition from original to new values
keyframes_css += f"""
@keyframes {animation_name} {{
0% {{
font-size: {orig_font_size};
letter-spacing: {orig_letter_spacing};
color: {orig_color};
text-shadow: {orig_text_shadow};
transform: skew({orig_skew_angle}) scale(1);
top: {orig_top};
margin-top: {orig_margin_top};
}}
25% {{
font-size: {new_font_size};
letter-spacing: {new_letter_spacing};
color: {word_color};
text-shadow: {new_text_shadow};
transform: skew({new_skew_angle}) scale(1.2);
top: {new_top};
margin-top: {new_margin_top};
}}
50% {{
transform: skew({new_skew_angle}) scale(0.9);
}}
75% {{
transform: skew({new_skew_angle}) scale(1.1);
}}
100% {{
font-size: {new_font_size};
letter-spacing: {new_letter_spacing};
color: {word_color};
text-shadow: {new_text_shadow};
transform: skew({new_skew_angle}) scale(1);
top: {new_top};
margin-top: {new_margin_top};
}}
}}
"""
style = {
'font-family': new_font_family, # Font changes instantly
'line-height': '1.6',
'font-size': new_font_size,
'letter-spacing': new_letter_spacing,
'text-shadow': new_text_shadow,
'transform': f'skew({new_skew_angle})',
'margin-top': new_margin_top,
'position': 'relative',
'top': new_top,
'color': word_color, # Same color for all letters in this word
'display': 'inline-block',
'margin': '0 1px',
'vertical-align': 'middle',
'animation': f'{animation_name} 2.5s ease-in-out forwards',
'animation-delay': f'{i * 0.1}s'
}
style_str = '; '.join([f'{k}: {v}' for k, v in style.items()])
styled_letter = f'<span class="letter-{word_id}-{i}" style="{style_str}">{letter}</span>'
styled_letters.append(styled_letter)
return f'''
{f"<style>{keyframes_css}</style>" if keyframes_css else ""}
<span class="word-container" id="word-{word_id}" style="display: inline-block;
margin: 10px;
padding: 8px 12px;
border: 2px solid #333;
border-radius: 8px;
background-color: rgba(255,255,255,0.8);">
<span style="display: inline-flex;
align-items: baseline;
vertical-align: middle;">
{" ".join(styled_letters)}
</span>
</span>'''
def generate_random_words():
"""Generate 5 random words with initial styling."""
global original_designs, selected_words
# Reset data
original_designs = {}
selected_words = random.sample(SPECIAL_WORDS, 5)
styled_words = []
for i, word in enumerate(selected_words):
word_design = generate_word_design(word, i, is_animated=False)
styled_words.append(word_design)
final_output = f"""
<html>
<head>
<link href="https://fonts.googleapis.com/css2?family=VT323&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@100&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Rajdhani:wght@300&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Anton&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Caveat&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Patrick+Hand&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Nothing+You+Could+Do&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Reenie+Beanie&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Orbitron&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Raleway:500" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Open+Sans+Condensed:wght@300&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Poiret+One&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Indie+Flower&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Pacifico&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Teko&display=swap" rel="stylesheet">
<style>
body {{
background-color: #f5f5f5;
color: #000;
font-size: 18px;
line-height: 1.6;
font-family: "Josefin Sans", sans-serif;
padding: 20px;
}}
</style>
</head>
<body>
<div style='max-width: 800px; margin: auto; text-align: center;'>
<h2 style="margin-bottom: 30px;">Random Styled Words</h2>
<div id="words-container" style="display: flex; flex-wrap: wrap; justify-content: center; align-items: center;">
{" ".join(styled_words)}
</div>
</div>
</body>
</html>
"""
return final_output
def trigger_movement(input_html):
"""Replace words with animated versions that transition from original to new styling."""
global original_designs, selected_words
if not original_designs or not selected_words:
return input_html
updated_html = input_html
# Replace each word with its animated version
for i, word in enumerate(selected_words):
if i in original_designs:
# Generate animated version that transitions from original values
animated_design = generate_word_design(word, i, is_animated=True)
# Find and replace the original word container
old_pattern = f'<span class="word-container" id="word-{i}"'
old_end = '</span></span>'
# Find the full original word HTML
start_idx = updated_html.find(old_pattern)
if start_idx != -1:
# Find the end of this word container
temp_html = updated_html[start_idx:]
span_count = 0
end_idx = start_idx
for j, char in enumerate(temp_html):
if temp_html[j:j+5] == '<span':
span_count += 1
elif temp_html[j:j+7] == '</span>':
span_count -= 1
if span_count == 0:
end_idx = start_idx + j + 7
break
if end_idx > start_idx:
old_word_html = updated_html[start_idx:end_idx]
updated_html = updated_html.replace(old_word_html, animated_design, 1)
return updated_html
# Create Gradio interface using Blocks
with gr.Blocks() as demo:
gr.Markdown("# Random Word Styler\nEach word gets ONE color and transitions from original to new styling!")
generate_button = gr.Button("Generate Random Words", variant="primary")
output_html = gr.HTML()
animate_button = gr.Button("Trigger Progressive Movement", variant="secondary")
generate_button.click(generate_random_words, outputs=output_html)
animate_button.click(trigger_movement, inputs=output_html, outputs=output_html)
# Launch the app
demo.launch()