circulartext's picture
Update app.py
2608ee0 verified
import gradio as gr
import random
# Your predefined words list
SPECIAL_WORDS = [
'luke', 'skywalker', 'vader', 'darth', 'leia', 'han', 'solo', 'chewbacca', 'obi-wan', 'kenobi',
'yoda', 'anakin', 'padme', 'amidala', 'palpatine', 'emperor', 'mace', 'windu', 'qui-gon', 'jinn',
'boba', 'fett', 'jango', 'rey', 'finn', 'poe', 'dameron', 'kylo', 'ren', 'snoke',
'hux', 'phasma', 'ahsoka', 'tano', 'grievous', 'dooku', 'maul', 'jabba', 'hutt', 'lando',
'calrissian', 'wedge', 'antilles', 'tarkin', 'thrawn', 'krennic', 'jyn', 'erso', 'cassian', 'andor',
'jedi', 'sith', 'force', 'lightsaber', 'empire', 'rebellion', 'republic', 'resistance', 'first', 'order',
'stormtrooper', 'clone', 'trooper', 'mandalorian', 'bounty', 'hunter', 'smuggler', 'pilot', 'princess', 'master',
'apprentice', 'padawan', 'senator', 'chancellor', 'admiral', 'general', 'commander', 'captain', 'lord', 'knight',
'millennium', 'falcon', 'x-wing', 'tie', 'fighter', 'star', 'destroyer', 'death', 'star', 'at-at',
'at-st', 'speeder', 'bike', 'podracer', 'landspeeder', 'transport', 'cruiser', 'frigate', 'corvette', 'dreadnought',
'tatooine', 'coruscant', 'endor', 'hoth', 'dagobah', 'naboo', 'alderaan', 'kamino', 'geonosis', 'mustafar',
'yavin', 'jakku', 'takodana', 'starkiller', 'base', 'cantina', 'sarlacc', 'pit', 'cloud', 'city',
'mos', 'eisley', 'jedi', 'temple', 'senate', 'cantina', 'carbon', 'freezing', 'hologram', 'droid',
'r2-d2', 'c-3po', 'bb-8', 'protocol', 'astromech', 'battle', 'super', 'destroyer', 'medical',
'blaster', 'thermal', 'detonator', 'holochess', 'hyperdrive', 'carbonite', 'kyber', 'crystal', 'holocron', 'meditation',
'training', 'younglings', 'prophecy', 'chosen', 'one', 'balance', 'dark', 'side', 'light', 'council',
'trials', 'vision', 'destiny', 'hope', 'rebellion', 'alliance', 'imperial', 'galactic', 'civil', 'war',
'clone', 'wars', 'separatist', 'confederacy', 'trade', 'federation', 'blockade', 'invasion', 'phantom', 'menace'
]
# 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()