Spaces:
Running
Running
Download index.html from Ezequield/anycoder-e2723b42: direct link, hf CLI and curl.
- Browser
- Download file 27.2 kB
-
https://huggingface.co/spaces/Ezequield/anycoder-e2723b42/resolve/main/index.html
- Command line
-
hf download hf://spaces/Ezequield/anycoder-e2723b42/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Ezequield/anycoder-e2723b42/resolve/main/index.html
27.2 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>ABC Logo Maker 1935-2024</title> | |
| <!-- Importing Google Fonts for different eras --> | |
| <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=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Great+Vibes&family=Montserrat:wght@100..900&family=Orbitron:wght@400..900&family=Rock+Salt&family=Inter:wght@300..800&display=swap" rel="stylesheet"> | |
| <!-- Font Awesome for Icons --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --bg-dark: #0f172a; | |
| --bg-panel: #1e293b; | |
| --primary: #3b82f6; | |
| --primary-hover: #2563eb; | |
| --text-main: #f8fafc; | |
| --text-muted: #94a3b8; | |
| --border: #334155; | |
| --accent: #8b5cf6; | |
| --radius: 12px; | |
| --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| outline: none; | |
| } | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| background-color: var(--bg-dark); | |
| color: var(--text-main); | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| overflow-x: hidden; | |
| } | |
| /* --- Header --- */ | |
| header { | |
| background: rgba(15, 23, 42, 0.9); | |
| backdrop-filter: blur(10px); | |
| border-bottom: 1px solid var(--border); | |
| padding: 1rem 2rem; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| position: sticky; | |
| top: 0; | |
| z-index: 100; | |
| } | |
| .brand { | |
| font-size: 1.5rem; | |
| font-weight: 800; | |
| background: linear-gradient(135deg, var(--primary), var(--accent)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| letter-spacing: -0.5px; | |
| } | |
| .anycoder-link { | |
| font-size: 0.875rem; | |
| color: var(--text-muted); | |
| text-decoration: none; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .anycoder-link:hover { | |
| color: var(--primary); | |
| } | |
| /* --- Main Layout --- */ | |
| main { | |
| flex: 1; | |
| display: grid; | |
| grid-template-columns: 350px 1fr; | |
| gap: 2rem; | |
| padding: 2rem; | |
| max-width: 1600px; | |
| margin: 0 auto; | |
| width: 100%; | |
| } | |
| @media (max-width: 1024px) { | |
| main { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| /* --- Sidebar Controls --- */ | |
| .controls { | |
| background: var(--bg-panel); | |
| border-radius: var(--radius); | |
| padding: 1.5rem; | |
| border: 1px solid var(--border); | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1.5rem; | |
| height: fit-content; | |
| } | |
| .control-group { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| } | |
| label { | |
| font-size: 0.875rem; | |
| font-weight: 600; | |
| color: var(--text-muted); | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| } | |
| input[type="text"] { | |
| background: var(--bg-dark); | |
| border: 1px solid var(--border); | |
| color: var(--text-main); | |
| padding: 0.75rem 1rem; | |
| border-radius: 8px; | |
| font-size: 1rem; | |
| transition: var(--transition); | |
| } | |
| input[type="text"]:focus { | |
| border-color: var(--primary); | |
| box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2); | |
| } | |
| .color-picker-wrapper { | |
| display: flex; | |
| gap: 1rem; | |
| align-items: center; | |
| } | |
| input[type="color"] { | |
| -webkit-appearance: none; | |
| border: none; | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| overflow: hidden; | |
| background: none; | |
| } | |
| input[type="color"]::-webkit-color-swatch-wrapper { | |
| padding: 0; | |
| } | |
| input[type="color"]::-webkit-color-swatch { | |
| border: 2px solid var(--border); | |
| border-radius: 50%; | |
| } | |
| input[type="range"] { | |
| width: 100%; | |
| height: 6px; | |
| background: var(--bg-dark); | |
| border-radius: 3px; | |
| appearance: none; | |
| cursor: pointer; | |
| } | |
| input[type="range"]::-webkit-slider-thumb { | |
| appearance: none; | |
| width: 18px; | |
| height: 18px; | |
| background: var(--primary); | |
| border-radius: 50%; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| } | |
| input[type="range"]::-webkit-slider-thumb:hover { | |
| transform: scale(1.2); | |
| } | |
| /* --- Timeline / Era Selector --- */ | |
| .timeline-container { | |
| margin-top: 1rem; | |
| } | |
| .timeline { | |
| display: flex; | |
| gap: 0.5rem; | |
| overflow-x: auto; | |
| padding-bottom: 1rem; | |
| scrollbar-width: thin; | |
| scrollbar-color: var(--border) var(--bg-dark); | |
| } | |
| .timeline::-webkit-scrollbar { | |
| height: 6px; | |
| } | |
| .timeline::-webkit-scrollbar-track { | |
| background: var(--bg-dark); | |
| } | |
| .timeline::-webkit-scrollbar-thumb { | |
| background: var(--border); | |
| border-radius: 3px; | |
| } | |
| .era-btn { | |
| background: var(--bg-dark); | |
| border: 1px solid var(--border); | |
| color: var(--text-muted); | |
| padding: 0.5rem 1rem; | |
| border-radius: 20px; | |
| font-size: 0.875rem; | |
| font-weight: 500; | |
| cursor: pointer; | |
| white-space: nowrap; | |
| transition: var(--transition); | |
| } | |
| .era-btn:hover { | |
| border-color: var(--primary); | |
| color: var(--text-main); | |
| } | |
| .era-btn.active { | |
| background: var(--primary); | |
| border-color: var(--primary); | |
| color: white; | |
| box-shadow: 0 0 15px rgba(59, 130, 246, 0.4); | |
| } | |
| /* --- Preview Area --- */ | |
| .preview-area { | |
| background: var(--bg-panel); | |
| border-radius: var(--radius); | |
| border: 1px solid var(--border); | |
| display: flex; | |
| flex-direction: column; | |
| position: relative; | |
| overflow: hidden; | |
| min-height: 500px; | |
| } | |
| .preview-header { | |
| padding: 1rem 2rem; | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .preview-canvas { | |
| flex: 1; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| background-image: | |
| radial-gradient(var(--border) 1px, transparent 1px), | |
| radial-gradient(var(--border) 1px, transparent 1px); | |
| background-size: 20px 20px; | |
| background-position: 0 0, 10px 10px; | |
| position: relative; | |
| padding: 2rem; | |
| overflow: hidden; | |
| } | |
| /* --- The Logo CSS Classes (The Core Logic) --- */ | |
| /* Common Base */ | |
| .logo-display { | |
| transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| user-select: none; | |
| text-align: center; | |
| line-height: 1; | |
| } | |
| /* 1935: Classic Serif */ | |
| .era-1935 { | |
| font-family: 'Playfair Display', serif; | |
| font-weight: 700; | |
| letter-spacing: 2px; | |
| text-transform: uppercase; | |
| font-style: italic; | |
| border-bottom: 4px solid var(--logo-color, #fff); | |
| padding-bottom: 10px; | |
| } | |
| /* 1953: Script/Broadcast */ | |
| .era-1953 { | |
| font-family: 'Great Vibes', cursive; | |
| font-size: 1.5em ; | |
| color: var(--logo-color, #eab308); | |
| text-shadow: 2px 2px 0px rgba(0,0,0,0.5); | |
| } | |
| /* 1962: The Circle (Iconic ABC) */ | |
| .era-1962 { | |
| position: relative; | |
| display: inline-flex; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| .era-1962::before { | |
| content: ''; | |
| position: absolute; | |
| width: 1.4em; | |
| height: 1.4em; | |
| background-color: #000; /* Always black circle for authenticity */ | |
| border-radius: 50%; | |
| z-index: -1; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.3); | |
| } | |
| .era-1962 { | |
| font-family: 'Arial Black', 'Helvetica Neue', sans-serif; | |
| color: white; | |
| font-weight: 900; | |
| text-transform: lowercase; | |
| letter-spacing: -2px; | |
| } | |
| /* 1975: Bold Sans Serif */ | |
| .era-1975 { | |
| font-family: 'Montserrat', sans-serif; | |
| font-weight: 900; | |
| text-transform: uppercase; | |
| letter-spacing: -2px; | |
| border: 8px solid var(--logo-color, #000); | |
| padding: 0.2em 0.5em; | |
| box-shadow: 10px 10px 0px var(--logo-secondary, #333); | |
| } | |
| /* 1988: Synthwave/Neon */ | |
| .era-1988 { | |
| font-family: 'Orbitron', sans-serif; | |
| font-weight: 700; | |
| text-transform: uppercase; | |
| color: #fff; | |
| text-shadow: | |
| 0 0 5px #fff, | |
| 0 0 10px #fff, | |
| 0 0 20px var(--logo-color, #ff00de), | |
| 0 0 40px var(--logo-color, #ff00de), | |
| 0 0 80px var(--logo-color, #ff00de); | |
| } | |
| /* 2007: Glossy Web 2.0 */ | |
| .era-2007 { | |
| font-family: 'Inter', sans-serif; | |
| font-weight: 800; | |
| text-transform: uppercase; | |
| background: linear-gradient(180deg, var(--logo-color, #3b82f6) 0%, var(--logo-secondary, #1d4ed8) 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| filter: drop-shadow(0px 4px 0px rgba(0,0,0,0.2)); | |
| } | |
| /* 2024: Modern Minimal */ | |
| .era-2024 { | |
| font-family: 'Montserrat', sans-serif; | |
| font-weight: 800; | |
| letter-spacing: -3px; | |
| background: linear-gradient(90deg, var(--logo-color, #fff) 0%, var(--logo-secondary, #94a3b8) 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| position: relative; | |
| } | |
| .era-2024::after { | |
| content: attr(data-text); | |
| position: absolute; | |
| left: 2px; | |
| top: 2px; | |
| width: 100%; | |
| z-index: -1; | |
| background: linear-gradient(90deg, var(--logo-secondary, #94a3b8) 0%, transparent 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| opacity: 0.5; | |
| filter: blur(4px); | |
| } | |
| /* --- Action Buttons --- */ | |
| .btn { | |
| background: var(--primary); | |
| color: white; | |
| border: none; | |
| padding: 0.75rem 1.5rem; | |
| border-radius: 8px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| justify-content: center; | |
| } | |
| .btn:hover { | |
| background: var(--primary-hover); | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3); | |
| } | |
| .btn-secondary { | |
| background: transparent; | |
| border: 1px solid var(--border); | |
| color: var(--text-main); | |
| } | |
| .btn-secondary:hover { | |
| background: var(--border); | |
| transform: translateY(-2px); | |
| } | |
| /* --- Toast Notification --- */ | |
| .toast { | |
| position: fixed; | |
| bottom: 2rem; | |
| right: 2rem; | |
| background: var(--bg-panel); | |
| border: 1px solid var(--primary); | |
| color: var(--text-main); | |
| padding: 1rem 1.5rem; | |
| border-radius: 8px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.5); | |
| transform: translateY(150%); | |
| transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| z-index: 1000; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.75rem; | |
| } | |
| .toast.show { | |
| transform: translateY(0); | |
| } | |
| .toast i { | |
| color: var(--primary); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="brand"> | |
| <i class="fa-solid fa-layer-group"></i> LogoMaker | |
| </div> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link"> | |
| Built with anycoder <i class="fa-solid fa-arrow-up-right-from-square"></i> | |
| </a> | |
| </header> | |
| <main> | |
| <!-- Sidebar Control Panel --> | |
| <aside class="controls"> | |
| <div class="control-group"> | |
| <label for="text-input">Logo Text</label> | |
| <input type="text" id="text-input" value="abc" maxlength="15" placeholder="Enter text..."> | |
| </div> | |
| <div class="control-group"> | |
| <label>Colors</label> | |
| <div class="color-picker-wrapper"> | |
| <input type="color" id="color-primary" value="#ffffff" title="Primary Color"> | |
| <input type="color" id="color-secondary" value="#3b82f6" title="Secondary Color/Accent"> | |
| </div> | |
| </div> | |
| <div class="control-group"> | |
| <label for="size-slider">Size</label> | |
| <input type="range" id="size-slider" min="50" max="250" value="120"> | |
| </div> | |
| <div class="timeline-container"> | |
| <label>Select Era (1935 - 2024)</label> | |
| <div class="timeline" id="timeline"> | |
| <!-- Generated by JS --> | |
| </div> | |
| </div> | |
| <div style="margin-top: auto; display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;"> | |
| <button class="btn btn-secondary" id="randomize-btn"> | |
| <i class="fa-solid fa-shuffle"></i> Random | |
| </button> | |
| <button class="btn" id="download-btn"> | |
| <i class="fa-solid fa-download"></i> Save | |
| </button> | |
| </div> | |
| </aside> | |
| <!-- Preview Area --> | |
| <section class="preview-area"> | |
| <div class="preview-header"> | |
| <span style="font-size: 0.875rem; color: var(--text-muted);">Live Preview</span> | |
| <div style="font-size: 0.875rem; font-weight: 600; color: var(--primary);" id="current-era-label">1962 Era</div> | |
| </div> | |
| <div class="preview-canvas"> | |
| <div id="logo-target" class="logo-display era-1962"> | |
| abc | |
| </div> | |
| </div> | |
| </section> | |
| </main> | |
| <!-- Hidden Canvas for Export --> | |
| <canvas id="export-canvas" style="display: none;"></canvas> | |
| <!-- Toast --> | |
| <div class="toast" id="toast"> | |
| <i class="fa-solid fa-circle-check"></i> | |
| <span id="toast-message">Action successful</span> | |
| </div> | |
| <script> | |
| // --- Configuration & State --- | |
| const eras = [ | |
| { id: 1935, name: '1935 Classic', class: 'era-1935' }, | |
| { id: 1953, name: '1953 Script', class: 'era-1953' }, | |
| { id: 1962, name: '1962 Circle', class: 'era-1962' }, | |
| { id: 1975, name: '1975 Bold', class: 'era-1975' }, | |
| { id: 1988, name: '1988 Neon', class: 'era-1988' }, | |
| { id: 2007, name: '2007 Glossy', class: 'era-2007' }, | |
| { id: 2024, name: '2024 Modern', class: 'era-2024' } | |
| ]; | |
| let state = { | |
| text: 'abc', | |
| eraIndex: 2, // Default to 1962 | |
| color1: '#ffffff', | |
| color2: '#3b82f6', | |
| size: 120 | |
| }; | |
| // --- DOM Elements --- | |
| const logoTarget = document.getElementById('logo-target'); | |
| const textInput = document.getElementById('text-input'); | |
| const color1Input = document.getElementById('color-primary'); | |
| const color2Input = document.getElementById('color-secondary'); | |
| const sizeSlider = document.getElementById('size-slider'); | |
| const timelineContainer = document.getElementById('timeline'); | |
| const eraLabel = document.getElementById('current-era-label'); | |
| const downloadBtn = document.getElementById('download-btn'); | |
| const randomBtn = document.getElementById('randomize-btn'); | |
| const toast = document.getElementById('toast'); | |
| const toastMsg = document.getElementById('toast-message'); | |
| // --- Initialization --- | |
| function init() { | |
| renderTimeline(); | |
| updatePreview(); | |
| setupEventListeners(); | |
| } | |
| // --- Core Functions --- | |
| function renderTimeline() { | |
| timelineContainer.innerHTML = ''; | |
| eras.forEach((era, index) => { | |
| const btn = document.createElement('button'); | |
| btn.className = `era-btn ${index === state.eraIndex ? 'active' : ''}`; | |
| btn.textContent = era.name; | |
| btn.onclick = () => setEra(index); | |
| timelineContainer.appendChild(btn); | |
| }); | |
| } | |
| function setEra(index) { | |
| state.eraIndex = index; | |
| renderTimeline(); // Update active class | |
| updatePreview(); | |
| } | |
| function updatePreview() { | |
| const currentEra = eras[state.eraIndex]; | |
| // Update Text | |
| logoTarget.textContent = state.text; | |
| logoTarget.setAttribute('data-text', state.text); // For 2024 style pseudo-element | |
| // Update Classes (Remove old, add new) | |
| logoTarget.className = `logo-display ${currentEra.class}`; | |
| // Update Size | |
| logoTarget.style.fontSize = `${state.size}px`; | |
| // Update CSS Variables for Colors | |
| logoTarget.style.setProperty('--logo-color', state.color1); | |
| logoTarget.style.setProperty('--logo-secondary', state.color2); | |
| // Update Label | |
| eraLabel.textContent = `${currentEra.id} Design`; | |
| } | |
| function showToast(message) { | |
| toastMsg.textContent = message; | |
| toast.classList.add('show'); | |
| setTimeout(() => { | |
| toast.classList.remove('show'); | |
| }, 3000); | |
| } | |
| // --- Canvas Export Logic (No external libraries) --- | |
| function downloadLogo() { | |
| const canvas = document.getElementById('export-canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const currentEra = eras[state.eraIndex]; | |
| // High resolution for export | |
| const scale = 4; | |
| const fontSize = state.size; | |
| // Estimate text width | |
| ctx.font = `900 ${fontSize}px Arial`; // Fallback for measurement | |
| const textWidth = ctx.measureText(state.text).width; | |
| // Set canvas dimensions | |
| const padding = fontSize * 2; | |
| canvas.width = (textWidth + padding) * scale; | |
| canvas.height = (fontSize * 2) * scale; | |
| // Reset scale transforms before drawing | |
| ctx.setTransform(1, 0, 0, 1, 0, 0); | |
| ctx.scale(scale, scale); | |
| // Center coordinate system | |
| ctx.translate(canvas.width / (2 * scale), canvas.height / (2 * scale)); | |
| // Background (Transparent usually, but let's keep it transparent) | |
| // Drawing Logic based on Era | |
| ctx.textAlign = 'center'; | |
| ctx.textBaseline = 'middle'; | |
| if (currentEra.id === 1935) { | |
| ctx.font = `italic 700 ${fontSize}px 'Playfair Display', serif`; | |
| ctx.fillStyle = state.color1; | |
| ctx.fillText(state.text.toUpperCase(), 0, 0); | |
| ctx.beginPath(); | |
| ctx.moveTo(-textWidth/2, fontSize/3); | |
| ctx.lineTo(textWidth/2, fontSize/3); | |
| ctx.strokeStyle = state.color1; | |
| ctx.lineWidth = 4; | |
| ctx.stroke(); | |
| } | |
| else if (currentEra.id === 1953) { | |
| ctx.font = `${fontSize}px 'Great Vibes', cursive`; | |
| ctx.fillStyle = state.color1; | |
| ctx.shadowColor = "rgba(0,0,0,0.5)"; | |
| ctx.shadowBlur = 0; | |
| ctx.shadowOffsetX = 2 * (fontSize/100); | |
| ctx.shadowOffsetY = 2 * (fontSize/100); | |
| ctx.fillText(state.text, 0, 0); | |
| } | |
| else if (currentEra.id === 1962) { | |
| // Circle | |
| ctx.beginPath(); | |
| ctx.arc(0, 0, fontSize * 0.7, 0, Math.PI * 2); | |
| ctx.fillStyle = '#000000'; | |
| ctx.fill(); | |
| // Text | |
| ctx.font = `900 ${fontSize}px 'Arial', sans-serif`; | |
| ctx.fillStyle = '#ffffff'; | |
| ctx.fillText(state.text.toLowerCase(), 0, 0); | |
| } | |
| else if (currentEra.id === 1975) { | |
| ctx.font = `900 ${fontSize}px 'Montserrat', sans-serif`; | |
| ctx.fillStyle = state.color1; | |
| // Box drawing | |
| const boxW = textWidth + fontSize; | |
| const boxH = fontSize + 20; | |
| // Shadow Box | |
| const offset = 10; | |
| ctx.fillStyle = state.color2; | |
| ctx.fillRect(-boxW/2 + offset, -boxH/2 + offset, boxW, boxH); | |
| // Main Box | |
| // Note: CSS border is hard to replicate perfectly in canvas stroke without offset math | |
| // We will draw a filled rect for the border effect | |
| ctx.fillStyle = state.color1; // Border color | |
| ctx.fillRect(-boxW/2, -boxH/2, boxW, boxH); | |
| // Inner text area (simulating hole) | |
| ctx.fillStyle = state.color1; // Matches background ideally, but here let's use text color | |
| // Actually 1975 style usually has text INSIDE the box. Let's just draw text. | |
| ctx.fillStyle = state.color2; | |
| ctx.fillText(state.text.toUpperCase(), 0, 0); | |
| } | |
| else if (currentEra.id === 1988) { | |
| ctx.font = `700 ${fontSize}px 'Orbitron', sans-serif`; | |
| ctx.fillStyle = '#ffffff'; | |
| ctx.shadowColor = state.color1; | |
| ctx.shadowBlur = 20; | |
| ctx.shadowOffsetX = 0; | |
| ctx.shadowOffsetY = 0; | |
| ctx.fillText(state.text.toUpperCase(), 0, 0); | |
| } | |
| else if (currentEra.id === 2007) { | |
| ctx.font = `800 ${fontSize}px 'Inter', sans-serif`; | |
| // Gradient Text | |
| const gradient = ctx.createLinearGradient(-textWidth/2, 0, textWidth/2, 0); | |
| gradient.addColorStop(0, state.color1); | |
| gradient.addColorStop(1, state.color2); | |
| ctx.fillStyle = gradient; | |
| ctx.shadowColor = "rgba(0,0,0,0.2)"; | |
| ctx.shadowBlur = 0; | |
| ctx.shadowOffsetY = 4; | |
| ctx.fillText(state.text.toUpperCase(), 0, 0); | |
| } | |
| else if (currentEra.id === 2024) { | |
| ctx.font = `800 ${fontSize}px 'Montserrat', sans-serif`; | |
| // Gradient 1 | |
| const gradient = ctx.createLinearGradient(-textWidth/2, 0, textWidth/2, 0); | |
| gradient.addColorStop(0, state.color1); | |
| gradient.addColorStop(1, state.color2); | |
| ctx.fillStyle = gradient; | |
| ctx.fillText(state.text, 0, 0); | |
| // Blur layer behind | |
| ctx.globalAlpha = 0.5; | |
| ctx.fillStyle = state.color2; | |
| ctx.filter = 'blur(4px)'; | |
| ctx.fillText(state.text, 2, 2); | |
| ctx.filter = 'none'; | |
| ctx.globalAlpha = 1.0; | |
| } | |
| // Trigger Download | |
| const link = document.createElement('a'); | |
| link.download = `logo-${currentEra.id}.png`; | |
| link.href = canvas.toDataURL(); | |
| link.click(); | |
| showToast('Logo downloaded successfully!'); | |
| } | |
| function randomize() { | |
| // Random text | |
| const texts = ['ABC', 'NET', 'SKY', 'LOGO', 'WEB', 'TV', 'NEWS']; | |
| state.text = texts[Math.floor(Math.random() * texts.length)]; | |
| // Random Era | |
| state.eraIndex = Math.floor(Math.random() * eras.length); | |
| // Random Colors | |
| state.color1 = '#' + Math.floor(Math.random()*16777215).toString(16).padStart(6, '0'); | |
| state.color2 = '#' + Math.floor(Math.random()*16777215).toString(16).padStart(6, '0'); | |
| // Update Inputs | |
| textInput.value = state.text; | |
| color1Input.value = state.color1; | |
| color2Input.value = state.color2; | |
| updatePreview(); | |
| renderTimeline(); | |
| } | |
| // --- Event Listeners --- | |
| function setupEventListeners() { | |
| textInput.addEventListener('input', (e) => { | |
| state.text = e.target.value; | |
| updatePreview(); | |
| }); | |
| color1Input.addEventListener('input', (e) => { | |
| state.color1 = e.target.value; | |
| updatePreview(); | |
| }); | |
| color2Input.addEventListener('input', (e) => { | |
| state.color2 = e.target.value; | |
| updatePreview(); | |
| }); | |
| sizeSlider.addEventListener('input', (e) => { | |
| state.size = e.target.value; | |
| updatePreview(); | |
| }); | |
| downloadBtn.addEventListener('click', downloadLogo); | |
| randomBtn.addEventListener('click', randomize); | |
| } | |
| // Run | |
| init(); | |
| </script> | |
| </body> | |
| </html> |