Created
April 10, 2025 03:09
-
-
Save jddunn/48bc03f3a9f85ffd8ccf90c801f6cf93 to your computer and use it in GitHub Desktop.
Logomaker - LLM-written logo maker web app, in 1 HTML file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!-- https://manic.agency/blog/logomaker-an-experiment-in-human-computer-interaction-vibe-coding --> | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Logo Generator</title> | |
| <!-- Extended Google Fonts API --> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700;900&family=Audiowide&family=Bungee+Shade&family=Bungee&family=Bungee+Outline&family=Bungee+Hairline&family=Chakra+Petch:wght@700&family=Exo+2:wght@800&family=Megrim&family=Press+Start+2P&family=Rubik+Mono+One&family=Russo+One&family=Syne+Mono&family=VT323&family=Wallpoet&family=Faster+One&family=Teko:wght@700&family=Black+Ops+One&family=Bai+Jamjuree:wght@700&family=Righteous&family=Bangers&family=Raleway+Dots&family=Monoton&family=Syncopate:wght@700&family=Lexend+Mega:wght@800&family=Michroma&family=Iceland&family=ZCOOL+QingKe+HuangYou&family=Zen+Tokyo+Zoo&family=Major+Mono+Display&family=Nova+Square&family=Kelly+Slab&family=Graduate&family=Unica+One&family=Aldrich&family=Share+Tech+Mono&family=Silkscreen&family=Rajdhani:wght@700&family=Jura:wght@700&family=Goldman&family=Tourney:wght@700&family=Saira+Stencil+One&family=Syncopate&family=Fira+Code:wght@700&family=DotGothic16&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --primary-gradient: linear-gradient( | |
| 45deg, | |
| #FF1493, /* Deep Pink */ | |
| #FF69B4, /* Hot Pink */ | |
| #FF00FF, /* Magenta */ | |
| #FF4500, /* Orange Red */ | |
| #8A2BE2 /* Blue Violet */ | |
| ); | |
| --cyberpunk-gradient: linear-gradient( | |
| 45deg, | |
| #00FFFF, /* Cyan */ | |
| #FF00FF, /* Magenta */ | |
| #FFFF00 /* Yellow */ | |
| ); | |
| --sunset-gradient: linear-gradient( | |
| 45deg, | |
| #FF7E5F, /* Coral */ | |
| #FEB47B, /* Peach */ | |
| #FF9966 /* Orange */ | |
| ); | |
| --ocean-gradient: linear-gradient( | |
| 45deg, | |
| #2E3192, /* Deep Blue */ | |
| #1BFFFF /* Light Cyan */ | |
| ); | |
| --forest-gradient: linear-gradient( | |
| 45deg, | |
| #134E5E, /* Deep Teal */ | |
| #71B280 /* Light Green */ | |
| ); | |
| --rainbow-gradient: linear-gradient( | |
| 45deg, | |
| #FF0000, /* Red */ | |
| #FF7F00, /* Orange */ | |
| #FFFF00, /* Yellow */ | |
| #00FF00, /* Green */ | |
| #0000FF, /* Blue */ | |
| #4B0082, /* Indigo */ | |
| #9400D3 /* Violet */ | |
| ); | |
| } | |
| body { | |
| display: flex; | |
| flex-direction: column; | |
| min-height: 100vh; | |
| margin: 0; | |
| background: #222; | |
| color: white; | |
| font-family: system-ui, -apple-system, sans-serif; | |
| padding: 20px; | |
| } | |
| header { | |
| text-align: center; | |
| margin-bottom: 20px; | |
| } | |
| h1 { | |
| margin: 0; | |
| font-size: 24px; | |
| color: #fff; | |
| } | |
| .container { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| width: 100%; | |
| } | |
| .controls-container { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 20px; | |
| width: 100%; | |
| margin-bottom: 30px; | |
| background: rgba(0, 0, 0, 0.2); | |
| padding: 20px; | |
| border-radius: 10px; | |
| } | |
| .control-group { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .control-group label { | |
| font-size: 14px; | |
| margin-bottom: 5px; | |
| color: #ccc; | |
| } | |
| input, select { | |
| padding: 8px; | |
| background: rgba(0, 0, 0, 0.5); | |
| border: 1px solid #555; | |
| color: #fff; | |
| border-radius: 4px; | |
| font-size: 14px; | |
| } | |
| input[type="color"] { | |
| height: 40px; | |
| } | |
| .preview-container { | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| width: 100%; | |
| margin-bottom: 30px; | |
| padding: 40px; | |
| background: #000; | |
| border-radius: 10px; | |
| position: relative; | |
| } | |
| .size-indicator { | |
| position: absolute; | |
| bottom: 5px; | |
| right: 10px; | |
| font-size: 12px; | |
| color: #555; | |
| } | |
| .logo-container { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| width: 100%; | |
| background: transparent; | |
| } | |
| .logo-text { | |
| font-size: 8vw; | |
| text-transform: uppercase; | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| color: transparent; | |
| background-size: 400% 400%; | |
| letter-spacing: 0.03em; | |
| line-height: 1; | |
| display: inline-block; | |
| padding: 20px; | |
| word-break: break-word; | |
| text-align: center; | |
| font-family: 'Orbitron', sans-serif; | |
| font-weight: 700; | |
| background-image: var(--primary-gradient); | |
| } | |
| /* Text shadow/glow presets */ | |
| .text-glow-none { | |
| text-shadow: none; | |
| filter: none; | |
| /* Make sure the text is visible even without glow */ | |
| -webkit-text-fill-color: transparent; | |
| color: transparent; | |
| } | |
| .text-glow-sharp { | |
| text-shadow: none; | |
| filter: none; | |
| -webkit-font-smoothing: none; | |
| -moz-osx-font-smoothing: none; | |
| font-smooth: never; | |
| /* Make sure the text is visible even with sharp edges */ | |
| -webkit-text-fill-color: transparent; | |
| color: transparent; | |
| } | |
| .text-glow-soft { | |
| /* Enhanced soft glow that's actually visible */ | |
| text-shadow: | |
| 0 0 1px rgba(255,255,255,0.9), | |
| 0 0 2px rgba(255,255,255,0.4); | |
| filter: none; | |
| -webkit-text-fill-color: transparent; | |
| color: transparent; | |
| } | |
| .text-glow-medium { | |
| text-shadow: | |
| 0 0 10px rgba(255,20,147,0.5), | |
| 0 0 20px rgba(255,105,180,0.3); | |
| filter: none; | |
| } | |
| .text-glow-hard { | |
| text-shadow: | |
| 0 0 7px rgba(255,255,255,0.7), | |
| 0 0 10px rgba(255,20,147,0.7), | |
| 0 0 20px rgba(255,105,180,0.5), | |
| 0 0 30px rgba(255,20,147,0.3); | |
| filter: none; | |
| } | |
| .text-glow-neon { | |
| text-shadow: | |
| 0 0 5px rgba(255,255,255,0.8), | |
| 0 0 10px currentColor, | |
| 0 0 20px currentColor, | |
| 0 0 30px currentColor, | |
| 0 0 40px currentColor; | |
| /* Need to make text visible for neon effect */ | |
| -webkit-text-fill-color: rgba(255, 255, 255, 0.8); | |
| color: rgba(255, 255, 255, 0.8); | |
| background-image: none !important; | |
| filter: none; | |
| } | |
| .text-glow-outline { | |
| -webkit-text-stroke: 2px rgba(255,255,255,0.8); | |
| text-shadow: none; | |
| filter: none; | |
| /* Make sure gradient still shows through */ | |
| -webkit-text-fill-color: transparent; | |
| color: transparent; | |
| } | |
| /* Background types */ | |
| .bg-transparent { | |
| background: transparent; | |
| } | |
| .bg-solid { | |
| background-color: #000000; | |
| } | |
| .bg-gradient { | |
| background: linear-gradient(135deg, #1a1a2e, #16213e, #0f3460); | |
| } | |
| .bg-gradient-animated { | |
| background: linear-gradient( | |
| -45deg, | |
| #1a1a2e, | |
| #16213e, | |
| #0f3460, | |
| #0a4b8b | |
| ); | |
| background-size: 400% 400%; | |
| animation: gradientBG 15s ease infinite; | |
| } | |
| .bg-transparent-gradient { | |
| background: linear-gradient(135deg, rgba(26,26,46,0.7), rgba(22,33,62,0.7), rgba(15,52,96,0.7)); | |
| } | |
| .bg-transparent-gradient-animated { | |
| background: linear-gradient( | |
| -45deg, | |
| rgba(26,26,46,0.7), | |
| rgba(22,33,62,0.7), | |
| rgba(15,52,96,0.7), | |
| rgba(10,75,139,0.7) | |
| ); | |
| background-size: 400% 400%; | |
| animation: gradientBG 15s ease infinite; | |
| } | |
| @keyframes gradientBG { | |
| 0% {background-position: 0% 50%;} | |
| 50% {background-position: 100% 50%;} | |
| 100% {background-position: 0% 50%;} | |
| } | |
| .bg-grid { | |
| background-color: rgba(0,0,0,0.9); | |
| background-image: | |
| linear-gradient(rgba(0, 255, 255, 0.1) 1px, transparent 1px), | |
| linear-gradient(90deg, rgba(0, 255, 255, 0.1) 1px, transparent 1px); | |
| background-size: 20px 20px; | |
| } | |
| .bg-darkgrid { | |
| background-color: rgba(10,10,10,0.9); | |
| background-image: | |
| linear-gradient(rgba(30, 30, 30, 1) 1px, transparent 1px), | |
| linear-gradient(90deg, rgba(30, 30, 30, 1) 1px, transparent 1px); | |
| background-size: 40px 40px; | |
| } | |
| .bg-stars { | |
| background-color: rgba(0,0,0,0.9); | |
| background-image: radial-gradient(white, rgba(255,255,255,.2) 2px, transparent 5px); | |
| background-size: 50px 50px; | |
| } | |
| .bg-noise { | |
| position: relative; | |
| background-color: rgba(0,0,0,0.8); | |
| } | |
| .bg-noise::before { | |
| content: ""; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 250 250' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); | |
| opacity: 0.2; | |
| z-index: -1; | |
| } | |
| /* Animation styles for the text */ | |
| .anim-none { | |
| animation: gradientShift 5s ease infinite; | |
| } | |
| .anim-blink { | |
| animation: gradientShift 5s ease infinite, blink 3s infinite; | |
| } | |
| .anim-pulse { | |
| animation: gradientShift 5s ease infinite, pulse 2s ease-in-out infinite; | |
| } | |
| .anim-bounce { | |
| animation: gradientShift 5s ease infinite, bounce 2s ease infinite; | |
| } | |
| .anim-shake { | |
| animation: gradientShift 5s ease infinite, shake 0.5s ease-in-out infinite; | |
| } | |
| .anim-typing { | |
| animation: gradientShift 5s ease infinite; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| border-right: 3px solid; | |
| width: 0; | |
| animation: gradientShift 5s ease infinite, typing 3.5s steps(40, end) forwards; | |
| } | |
| @keyframes blink { | |
| 0%, 19%, 21%, 23%, 71%, 73%, 75%, 100% { opacity: 1; } | |
| 20%, 22%, 24%, 72%, 74% { opacity: 0.5; } | |
| } | |
| @keyframes pulse { | |
| 0% { transform: scale(1); } | |
| 50% { transform: scale(1.05); } | |
| 100% { transform: scale(1); } | |
| } | |
| @keyframes bounce { | |
| 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } | |
| 40% { transform: translateY(-20px); } | |
| 60% { transform: translateY(-10px); } | |
| } | |
| @keyframes shake { | |
| 0%, 100% { transform: translateX(0); } | |
| 10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); } | |
| 20%, 40%, 60%, 80% { transform: translateX(5px); } | |
| } | |
| @keyframes typing { | |
| from { width: 0; } | |
| to { width: 100%; } | |
| } | |
| @keyframes gradientShift { | |
| 0% {background-position: 0% 50%;} | |
| 50% {background-position: 100% 50%;} | |
| 100% {background-position: 0% 50%;} | |
| } | |
| .button-container { | |
| display: flex; | |
| gap: 15px; | |
| justify-content: center; | |
| flex-wrap: wrap; | |
| width: 100%; | |
| } | |
| button { | |
| background: linear-gradient(135deg, #FF1493, #FF69B4); | |
| border: none; | |
| color: white; | |
| padding: 12px 20px; | |
| font-family: 'Orbitron', sans-serif; | |
| font-size: 1em; | |
| cursor: pointer; | |
| border-radius: 8px; | |
| box-shadow: 0 4px 6px rgba(0,0,0,0.2), 0 0 20px rgba(255,20,147,0.3); | |
| transition: all 0.3s ease; | |
| text-transform: uppercase; | |
| letter-spacing: 0.1em; | |
| } | |
| button:hover { | |
| transform: scale(1.05); | |
| background: linear-gradient(135deg, #FF69B4, #FF1493); | |
| box-shadow: 0 6px 8px rgba(0,0,0,0.3), 0 0 30px rgba(255,20,147,0.5); | |
| } | |
| .loading-indicator { | |
| display: none; | |
| margin-top: 20px; | |
| color: #fff; | |
| text-align: center; | |
| font-style: italic; | |
| } | |
| .font-preview { | |
| font-size: 20px; | |
| margin-left: 10px; | |
| display: inline-block; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <h1>Logo Generator</h1> | |
| </header> | |
| <div class="controls-container"> | |
| <div class="control-group"> | |
| <label for="logoText">Logo Text</label> | |
| <input type="text" id="logoText" value="MagicLogger" placeholder="Enter logo text"> | |
| </div> | |
| <div class="control-group"> | |
| <label for="fontFamily">Font Family <span id="fontPreview" class="font-preview">Aa</span></label> | |
| <select id="fontFamily"> | |
| <optgroup label="Popular Tech Fonts"> | |
| <option value="'Orbitron', sans-serif">Orbitron</option> | |
| <option value="'Audiowide', cursive">Audiowide</option> | |
| <option value="'Black Ops One', cursive">Black Ops One</option> | |
| <option value="'Russo One', sans-serif">Russo One</option> | |
| <option value="'Teko', sans-serif">Teko</option> | |
| <option value="'Rajdhani', sans-serif">Rajdhani</option> | |
| <option value="'Chakra Petch', sans-serif">Chakra Petch</option> | |
| <option value="'Michroma', sans-serif">Michroma</option> | |
| </optgroup> | |
| <optgroup label="Futuristic"> | |
| <option value="'Exo 2', sans-serif">Exo 2</option> | |
| <option value="'Jura', sans-serif">Jura</option> | |
| <option value="'Bai Jamjuree', sans-serif">Bai Jamjuree</option> | |
| <option value="'Aldrich', sans-serif">Aldrich</option> | |
| <option value="'Unica One', cursive">Unica One</option> | |
| <option value="'Goldman', cursive">Goldman</option> | |
| <option value="'Nova Square', cursive">Nova Square</option> | |
| </optgroup> | |
| <optgroup label="Decorative & Display"> | |
| <option value="'Bungee', cursive">Bungee</option> | |
| <option value="'Bungee Shade', cursive">Bungee Shade</option> | |
| <option value="'Bungee Outline', cursive">Bungee Outline</option> | |
| <option value="'Bungee Hairline', cursive">Bungee Hairline</option> | |
| <option value="'Righteous', cursive">Righteous</option> | |
| <option value="'Monoton', cursive">Monoton</option> | |
| <option value="'Bangers', cursive">Bangers</option> | |
| <option value="'Faster One', cursive">Faster One</option> | |
| <option value="'Tourney', cursive">Tourney</option> | |
| <option value="'Saira Stencil One', cursive">Saira Stencil One</option> | |
| <option value="'Zen Tokyo Zoo', cursive">Zen Tokyo Zoo</option> | |
| </optgroup> | |
| <optgroup label="Monospace & Pixel"> | |
| <option value="'Press Start 2P', cursive">Press Start 2P</option> | |
| <option value="'VT323', monospace">VT323</option> | |
| <option value="'Share Tech Mono', monospace">Share Tech Mono</option> | |
| <option value="'Fira Code', monospace">Fira Code</option> | |
| <option value="'Silkscreen', cursive">Silkscreen</option> | |
| <option value="'DotGothic16', sans-serif">DotGothic16</option> | |
| <option value="'Major Mono Display', monospace">Major Mono Display</option> | |
| <option value="'Syne Mono', monospace">Syne Mono</option> | |
| <option value="'Iceland', cursive">Iceland</option> | |
| </optgroup> | |
| <optgroup label="Unique & Stylized"> | |
| <option value="'Megrim', cursive">Megrim</option> | |
| <option value="'Rubik Mono One', sans-serif">Rubik Mono One</option> | |
| <option value="'Wallpoet', cursive">Wallpoet</option> | |
| <option value="'Lexend Mega', sans-serif">Lexend Mega</option> | |
| <option value="'Raleway Dots', cursive">Raleway Dots</option> | |
| <option value="'Syncopate', sans-serif">Syncopate</option> | |
| <option value="'ZCOOL QingKe HuangYou', cursive">ZCOOL QingKe HuangYou</option> | |
| <option value="'Kelly Slab', cursive">Kelly Slab</option> | |
| <option value="'Graduate', cursive">Graduate</option> | |
| </optgroup> | |
| </select> | |
| </div> | |
| <div class="control-group"> | |
| <label for="fontSize">Font Size (px)</label> | |
| <input type="number" id="fontSize" value="100" min="20" max="500"> | |
| </div> | |
| <div class="control-group"> | |
| <label for="letterSpacing">Letter Spacing</label> | |
| <input type="range" id="letterSpacing" min="0" max="0.5" step="0.01" value="0.03"> | |
| </div> | |
| <div class="control-group"> | |
| <label for="gradientPreset">Gradient Preset</label> | |
| <select id="gradientPreset"> | |
| <option value="var(--primary-gradient)">Pink Magenta</option> | |
| <option value="var(--cyberpunk-gradient)">Cyberpunk</option> | |
| <option value="var(--sunset-gradient)">Sunset</option> | |
| <option value="var(--ocean-gradient)">Ocean</option> | |
| <option value="var(--forest-gradient)">Forest</option> | |
| <option value="var(--rainbow-gradient)">Rainbow</option> | |
| <option value="custom">Custom...</option> | |
| </select> | |
| </div> | |
| <div class="control-group" id="customGradientControls" style="display: none;"> | |
| <label for="color1">Gradient Color 1</label> | |
| <input type="color" id="color1" value="#FF1493"> | |
| <label for="color2">Gradient Color 2</label> | |
| <input type="color" id="color2" value="#8A2BE2"> | |
| </div> | |
| <div class="control-group"> | |
| <label for="animationSpeed">Animation Speed</label> | |
| <input type="range" id="animationSpeed" min="1" max="10" value="5"> | |
| </div> | |
| <div class="control-group"> | |
| <label for="textShadow">Text Glow/Sharpness</label> | |
| <select id="textShadow"> | |
| <option value="none" selected>None (No Glow)</option> | |
| <option value="sharp">Sharp Edges</option> | |
| <option value="soft">Soft Glow</option> | |
| <option value="medium">Medium Glow</option> | |
| <option value="hard">Hard Glow</option> | |
| <option value="neon">Neon Effect</option> | |
| <option value="outline">Outline</option> | |
| </select> | |
| </div> | |
| <div class="control-group"> | |
| <label for="backgroundType">Background</label> | |
| <select id="backgroundType"> | |
| <option value="transparent">Transparent</option> | |
| <option value="transparent-gradient">Transparent Gradient</option> | |
| <option value="transparent-gradient-animated">Animated Transparent Gradient</option> | |
| <option value="solid">Solid Color</option> | |
| <option value="gradient">Gradient</option> | |
| <option value="gradient-animated">Animated Gradient</option> | |
| <option value="grid">Cyberpunk Grid</option> | |
| <option value="darkgrid">Dark Grid</option> | |
| <option value="stars">Starfield</option> | |
| <option value="noise">Digital Noise</option> | |
| </select> | |
| </div> | |
| <div class="control-group" id="backgroundColorControl" style="display: none;"> | |
| <label for="backgroundColor">Background Color</label> | |
| <input type="color" id="backgroundColor" value="#000000"> | |
| </div> | |
| <div class="control-group"> | |
| <label for="textAnimation">Text Animation</label> | |
| <select id="textAnimation"> | |
| <option value="none">None (Gradient Only)</option> | |
| <option value="blink">Blink</option> | |
| <option value="pulse">Pulse</option> | |
| <option value="bounce">Bounce</option> | |
| <option value="shake">Shake</option> | |
| <option value="typing">Typing</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="preview-container" id="previewContainer"> | |
| <div class="logo-container"> | |
| <div class="logo-text">MagicLogger</div> | |
| </div> | |
| <div class="size-indicator"><span id="logoWidth">0</span> x <span id="logoHeight">0</span>px</div> | |
| </div> | |
| <div class="button-container"> | |
| <button id="exportPngBtn">Export as PNG</button> | |
| <button id="exportGifBtn">Export as GIF</button> | |
| </div> | |
| <div id="loadingIndicator" class="loading-indicator"> | |
| Generating export... This may take a few moments. | |
| </div> | |
| </div> | |
| <!-- Scripts --> | |
| <script> | |
| // DOM elements | |
| const logoText = document.getElementById('logoText'); | |
| const fontFamily = document.getElementById('fontFamily'); | |
| const fontSize = document.getElementById('fontSize'); | |
| const letterSpacing = document.getElementById('letterSpacing'); | |
| const gradientPreset = document.getElementById('gradientPreset'); | |
| const customGradientControls = document.getElementById('customGradientControls'); | |
| const color1 = document.getElementById('color1'); | |
| const color2 = document.getElementById('color2'); | |
| const animationSpeed = document.getElementById('animationSpeed'); | |
| const textShadow = document.getElementById('textShadow'); | |
| const backgroundType = document.getElementById('backgroundType'); | |
| const backgroundColor = document.getElementById('backgroundColor'); | |
| const backgroundColorControl = document.getElementById('backgroundColorControl'); | |
| const textAnimation = document.getElementById('textAnimation'); | |
| const exportPngBtn = document.getElementById('exportPngBtn'); | |
| const exportGifBtn = document.getElementById('exportGifBtn'); | |
| const loadingIndicator = document.getElementById('loadingIndicator'); | |
| const logoElement = document.querySelector('.logo-text'); | |
| const previewContainer = document.getElementById('previewContainer'); | |
| const fontPreview = document.getElementById('fontPreview'); | |
| const logoWidth = document.getElementById('logoWidth'); | |
| const logoHeight = document.getElementById('logoHeight'); | |
| // Update logo size indicator | |
| function updateSizeIndicator() { | |
| logoWidth.textContent = logoElement.offsetWidth; | |
| logoHeight.textContent = logoElement.offsetHeight; | |
| } | |
| // Initialize | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Update logo text from input | |
| logoText.addEventListener('input', function() { | |
| logoElement.textContent = this.value || 'Logo'; | |
| updateSizeIndicator(); | |
| }); | |
| // Update font family | |
| fontFamily.addEventListener('change', function() { | |
| logoElement.style.fontFamily = this.value; | |
| fontPreview.style.fontFamily = this.value; | |
| updateSizeIndicator(); | |
| }); | |
| // Font preview text | |
| fontPreview.style.fontFamily = fontFamily.value; | |
| // Update font size | |
| fontSize.addEventListener('input', function() { | |
| logoElement.style.fontSize = this.value + 'px'; | |
| updateSizeIndicator(); | |
| }); | |
| // Update letter spacing | |
| letterSpacing.addEventListener('input', function() { | |
| logoElement.style.letterSpacing = this.value + 'em'; | |
| }); | |
| // Update gradient preset | |
| gradientPreset.addEventListener('change', function() { | |
| if (this.value === 'custom') { | |
| customGradientControls.style.display = 'block'; | |
| updateCustomGradient(); | |
| } else { | |
| customGradientControls.style.display = 'none'; | |
| logoElement.style.backgroundImage = this.value; | |
| } | |
| }); | |
| // Update custom gradient | |
| function updateCustomGradient() { | |
| logoElement.style.backgroundImage = `linear-gradient(45deg, ${color1.value}, ${color2.value})`; | |
| } | |
| color1.addEventListener('input', updateCustomGradient); | |
| color2.addEventListener('input', updateCustomGradient); | |
| // Update animation speed | |
| animationSpeed.addEventListener('input', function() { | |
| const seconds = 11 - this.value; // Invert the scale (1-10) -> (10-1) | |
| logoElement.style.animationDuration = seconds + 's'; | |
| }); | |
| // Update text shadow/glow | |
| textShadow.addEventListener('change', function() { | |
| // Remove all previous glow classes | |
| logoElement.classList.remove( | |
| 'text-glow-none', | |
| 'text-glow-soft', | |
| 'text-glow-medium', | |
| 'text-glow-hard', | |
| 'text-glow-neon', | |
| 'text-glow-outline', | |
| 'text-glow-sharp' | |
| ); | |
| // Add the selected glow class | |
| logoElement.classList.add('text-glow-' + this.value); | |
| }); | |
| // Update text animation | |
| textAnimation.addEventListener('change', function() { | |
| // Remove all previous animation classes | |
| logoElement.classList.remove( | |
| 'anim-none', | |
| 'anim-blink', | |
| 'anim-pulse', | |
| 'anim-bounce', | |
| 'anim-shake', | |
| 'anim-typing' | |
| ); | |
| // Add the selected animation class | |
| logoElement.classList.add('anim-' + this.value); | |
| }); | |
| // Update background | |
| backgroundType.addEventListener('change', function() { | |
| // Remove all previous background classes | |
| previewContainer.classList.remove( | |
| 'bg-transparent', | |
| 'bg-transparent-gradient', | |
| 'bg-transparent-gradient-animated', | |
| 'bg-solid', | |
| 'bg-gradient', | |
| 'bg-gradient-animated', | |
| 'bg-grid', | |
| 'bg-darkgrid', | |
| 'bg-stars', | |
| 'bg-noise' | |
| ); | |
| // Add the selected background class | |
| previewContainer.classList.add('bg-' + this.value); | |
| // Show/hide background color control | |
| backgroundColorControl.style.display = | |
| (this.value === 'solid') ? 'block' : 'none'; | |
| }); | |
| // Update background color | |
| backgroundColor.addEventListener('input', function() { | |
| previewContainer.style.backgroundColor = this.value; | |
| }); | |
| // Set initial font size | |
| logoElement.style.fontSize = fontSize.value + 'px'; | |
| // Set initial letter spacing | |
| logoElement.style.letterSpacing = letterSpacing.value + 'em'; | |
| // Set initial text glow | |
| logoElement.classList.add('text-glow-none'); | |
| // Set initial text animation | |
| logoElement.classList.add('anim-none'); | |
| // Set initial background | |
| previewContainer.classList.add('bg-transparent'); | |
| // Update size on window resize | |
| window.addEventListener('resize', updateSizeIndicator); | |
| // Initial size update | |
| updateSizeIndicator(); | |
| // Load external libraries | |
| loadExternalLibraries(); | |
| }); | |
| // Load required libraries | |
| function loadExternalLibraries() { | |
| // Load dom-to-image for PNG export | |
| var domToImageScript = document.createElement('script'); | |
| domToImageScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.min.js'; | |
| domToImageScript.onload = function() { | |
| console.log('dom-to-image library loaded'); | |
| exportPngBtn.disabled = false; | |
| }; | |
| domToImageScript.onerror = function() { | |
| console.error('Failed to load dom-to-image library'); | |
| alert('Error loading PNG export library'); | |
| }; | |
| document.head.appendChild(domToImageScript); | |
| // Load gif.js for GIF export | |
| var gifScript = document.createElement('script'); | |
| gifScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/gif.js/0.2.0/gif.js'; | |
| gifScript.onload = function() { | |
| console.log('gif.js library loaded'); | |
| exportGifBtn.disabled = false; | |
| }; | |
| gifScript.onerror = function() { | |
| console.error('Failed to load gif.js library'); | |
| alert('Error loading GIF export library'); | |
| }; | |
| document.head.appendChild(gifScript); | |
| } | |
| // Export as PNG | |
| exportPngBtn.addEventListener('click', function() { | |
| // Show loading indicator | |
| loadingIndicator.style.display = 'block'; | |
| // Temporarily pause animation | |
| const originalAnimationState = logoElement.style.animationPlayState; | |
| logoElement.style.animationPlayState = 'paused'; | |
| // Determine what to capture based on background type | |
| const captureElement = (backgroundType.value !== 'transparent') ? | |
| previewContainer : logoElement; | |
| // Use dom-to-image for PNG export | |
| domtoimage.toPng(captureElement, { | |
| bgcolor: null, | |
| height: captureElement.offsetHeight, | |
| width: captureElement.offsetWidth, | |
| style: { | |
| margin: '0', | |
| padding: backgroundType.value !== 'transparent' ? '40px' : '20px' | |
| } | |
| }) | |
| .then(function(dataUrl) { | |
| // Restore animation | |
| logoElement.style.animationPlayState = originalAnimationState; | |
| // Create download link | |
| const link = document.createElement('a'); | |
| link.download = logoText.value.replace(/\s+/g, '-').toLowerCase() + '-logo.png'; | |
| link.href = dataUrl; | |
| link.click(); | |
| // Hide loading indicator | |
| loadingIndicator.style.display = 'none'; | |
| }) | |
| .catch(function(error) { | |
| console.error('Error exporting PNG:', error); | |
| logoElement.style.animationPlayState = originalAnimationState; | |
| loadingIndicator.style.display = 'none'; | |
| alert('Failed to export PNG. Please try again.'); | |
| }); | |
| }); | |
| // Export as GIF | |
| exportGifBtn.addEventListener('click', function() { | |
| if (typeof GIF === 'undefined') { | |
| alert('GIF library not loaded yet. Please try again in a moment.'); | |
| return; | |
| } | |
| // Show loading indicator | |
| loadingIndicator.style.display = 'block'; | |
| // Store current animation state | |
| const originalAnimationState = logoElement.style.animationPlayState; | |
| // Create a GIF | |
| const gif = new GIF({ | |
| workers: 2, | |
| quality: 10, | |
| width: logoElement.offsetWidth, | |
| height: logoElement.offsetHeight, | |
| transparent: true, | |
| workerScript: 'https://cdnjs.cloudflare.com/ajax/libs/gif.js/0.2.0/gif.worker.js' | |
| }); | |
| // Frame count and duration | |
| const frames = 20; | |
| const duration = 100; // ms per frame | |
| // Capture the entire preview container for frames if background is selected | |
| const captureElement = (backgroundType.value !== 'transparent') ? | |
| document.getElementById('previewContainer') : logoElement; | |
| // Capture frames of the animation | |
| captureFrames(0, frames, duration); | |
| function captureFrames(currentFrame, totalFrames, frameDuration) { | |
| if (currentFrame >= totalFrames) { | |
| // All frames captured, render the GIF | |
| gif.render(); | |
| return; | |
| } | |
| // Calculate animation progress percentage | |
| const progress = (currentFrame / totalFrames) * 100; | |
| logoElement.style.backgroundPosition = `${progress}% 50%`; | |
| // Capture current frame | |
| domtoimage.toPixelData(captureElement) | |
| .then(function(pixels) { | |
| // Add frame to GIF | |
| gif.addFrame(pixels, {delay: frameDuration, copy: true}); | |
| // Capture next frame | |
| captureFrames(currentFrame + 1, totalFrames, frameDuration); | |
| }) | |
| .catch(function(error) { | |
| console.error('Error capturing GIF frame:', error); | |
| logoElement.style.animationPlayState = originalAnimationState; | |
| loadingIndicator.style.display = 'none'; | |
| alert('Failed to create GIF. Please try again.'); | |
| }); | |
| } | |
| // GIF rendering complete | |
| gif.on('finished', function(blob) { | |
| // Restore animation | |
| logoElement.style.animationPlayState = originalAnimationState; | |
| // Create download link | |
| const url = URL.createObjectURL(blob); | |
| const link = document.createElement('a'); | |
| link.download = logoText.value.replace(/\s+/g, '-').toLowerCase() + '-logo.gif'; | |
| link.href = url; | |
| link.click(); | |
| // Clean up | |
| setTimeout(() => URL.revokeObjectURL(url), 100); | |
| // Hide loading indicator | |
| loadingIndicator.style.display = 'none'; | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment