import gradio as gr import random import time import re # === Your original per-letter styling algorithm === def generate_initial_design(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" ] font_sizes = ["18px", "19px", "20px"] font_tops = ["0px", "1px", "-1px"] letter_spacings = ["-1px", "0px", "1px"] text_shadows = [ "0px 0px 1px", "0px 0px 2px", "1px 0px 0px", "0px 0px 0px", "0px 1px 0px", "0px 2px 0px", "0px 1px 1px", "1px 1px 0px", "1px 0px 1px" ] skew_angles = ["-25deg", "-20deg", "-15deg", "-10deg", "0deg", "10deg", "15deg", "20deg", "25deg"] letters = list(word) styled_letters = [] for letter in letters: style = { 'font-family': random.choice(fonts), 'line-height': '1.6', 'font-size': random.choice(font_sizes), 'letter-spacing': random.choice(letter_spacings), 'text-shadow': random.choice(text_shadows), 'transform': f'skew({random.choice(skew_angles)})', 'margin-top': random.choice(["-0.02cm", "0.00cm", "0.02cm"]), 'position': 'relative', 'top': random.choice(font_tops), 'color': '#000000', 'display': 'inline-block', 'margin': '0 1px', 'vertical-align': 'middle', 'cursor': 'pointer' } style_str = '; '.join([f'{k}: {v}' for k, v in style.items()]) styled_letter = f'{letter}' styled_letters.append(styled_letter) return f"{' '.join(styled_letters)}" # === Typing effect with your letter-by-letter styled special words === def typing_effect(): paragraphs = [ "Proctor's voice quavered, “Where are we, Benshiro? This can't be real. We went full speed into that...”", "“Proctor, I hear you! Is that you? I'm so thankful, but where are you? I can't see you.” Benshiro's words echoed in the void." ] html_output = "" for paragraph in paragraphs: words = paragraph.split() special_word = random.choice(words) styled_words = [generate_initial_design(w) if w == special_word else w for w in words] for w in styled_words: html_output += w + " " yield html_output time.sleep(0.05) html_output += "

" time.sleep(0.3) # === Re-randomize ALL styled letters on button click === def animate_letters(current_html): def re_style_letters(match): letter = match.group(1) return generate_initial_design(letter) if len(letter) > 1 else letter # Replace entire special word spans by regenerating styles for each letter return re.sub(r']*>([^<]+)', lambda m: f"{''.join(generate_initial_design(m.group(1)))}", current_html) # === Gradio UI === with gr.Blocks() as demo: gr.HTML("""""") gr.Markdown("## 🎨 Per-Letter Styled Typing Effect with Animation Button") output_html = gr.HTML() with gr.Row(): start_btn = gr.Button("▶ Start Typing") animate_btn = gr.Button("✨ Re-Randomize Styles") start_btn.click(typing_effect, outputs=output_html) animate_btn.click(animate_letters, inputs=output_html, outputs=output_html) demo.launch()