Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Pelican Cyclist Generator</title> | |
| <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=Outfit:wght@300;500;700&display=swap" rel="stylesheet"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #ff6b6b; | |
| --secondary: #4ecdc4; | |
| --dark: #2d3436; | |
| --light: #f7f1e3; | |
| --bg-gradient: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); | |
| --card-bg: rgba(255, 255, 255, 0.9); | |
| --shadow: 0 10px 30px rgba(0,0,0,0.1); | |
| --radius: 16px; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| font-family: 'Outfit', sans-serif; | |
| background: var(--bg-gradient); | |
| color: var(--dark); | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| /* Header */ | |
| header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 1.5rem 2rem; | |
| background: white; | |
| box-shadow: 0 2px 10px rgba(0,0,0,0.05); | |
| position: relative; | |
| z-index: 10; | |
| } | |
| .logo { | |
| font-weight: 700; | |
| font-size: 1.5rem; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .logo i { | |
| color: var(--primary); | |
| } | |
| .anycoder-link { | |
| text-decoration: none; | |
| color: var(--dark); | |
| font-weight: 500; | |
| background: #f0f0f0; | |
| padding: 0.5rem 1rem; | |
| border-radius: 50px; | |
| transition: all 0.3s ease; | |
| font-size: 0.9rem; | |
| } | |
| .anycoder-link:hover { | |
| background: var(--dark); | |
| color: white; | |
| transform: translateY(-2px); | |
| } | |
| /* Main Layout */ | |
| main { | |
| flex: 1; | |
| display: grid; | |
| grid-template-columns: 1fr 350px; | |
| gap: 2rem; | |
| padding: 2rem; | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| width: 100%; | |
| } | |
| /* Canvas Area */ | |
| .canvas-wrapper { | |
| background: var(--card-bg); | |
| border-radius: var(--radius); | |
| box-shadow: var(--shadow); | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| padding: 2rem; | |
| position: relative; | |
| overflow: hidden; | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255,255,255,0.5); | |
| } | |
| svg { | |
| width: 100%; | |
| height: 100%; | |
| max-height: 600px; | |
| filter: drop-shadow(0 10px 20px rgba(0,0,0,0.15)); | |
| } | |
| /* Controls Area */ | |
| .controls-wrapper { | |
| background: white; | |
| border-radius: var(--radius); | |
| box-shadow: var(--shadow); | |
| padding: 2rem; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1.5rem; | |
| height: fit-content; | |
| } | |
| .control-group { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| } | |
| label { | |
| font-weight: 500; | |
| font-size: 0.9rem; | |
| color: #636e72; | |
| } | |
| input[type="color"] { | |
| width: 100%; | |
| height: 40px; | |
| border: none; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| background: none; | |
| } | |
| input[type="range"] { | |
| width: 100%; | |
| accent-color: var(--primary); | |
| } | |
| .btn { | |
| border: none; | |
| padding: 1rem; | |
| border-radius: 12px; | |
| font-weight: 700; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 10px; | |
| font-family: inherit; | |
| } | |
| .btn-primary { | |
| background: var(--primary); | |
| color: white; | |
| box-shadow: 0 4px 15px rgba(255, 107, 107, 0.3); | |
| } | |
| .btn-primary:hover { | |
| background: #ff5252; | |
| transform: translateY(-2px); | |
| } | |
| .btn-secondary { | |
| background: var(--secondary); | |
| color: white; | |
| box-shadow: 0 4px 15px rgba(78, 205, 196, 0.3); | |
| } | |
| .btn-secondary:hover { | |
| background: #3dbdb3; | |
| transform: translateY(-2px); | |
| } | |
| /* SVG Animation Classes */ | |
| .wheel-rotate { | |
| animation: rotate 2s linear infinite; | |
| transform-box: fill-box; | |
| transform-origin: center; | |
| } | |
| .pelican-bounce { | |
| animation: bounce 1s ease-in-out infinite alternate; | |
| } | |
| .leg-pedal-l { | |
| animation: pedalLeft 2s linear infinite; | |
| transform-box: fill-box; | |
| transform-origin: top center; | |
| } | |
| .leg-pedal-r { | |
| animation: pedalRight 2s linear infinite; | |
| transform-box: fill-box; | |
| transform-origin: top center; | |
| } | |
| .cloud-move { | |
| animation: floatCloud 20s linear infinite; | |
| } | |
| @keyframes rotate { | |
| from { transform: rotate(0deg); } | |
| to { transform: rotate(360deg); } | |
| } | |
| @keyframes bounce { | |
| 0% { transform: translateY(0); } | |
| 100% { transform: translateY(-5px); } | |
| } | |
| @keyframes floatCloud { | |
| from { transform: translateX(850px); } | |
| to { transform: translateX(-200px); } | |
| } | |
| /* Responsive */ | |
| @media (max-width: 900px) { | |
| main { | |
| grid-template-columns: 1fr; | |
| } | |
| .canvas-wrapper { | |
| min-height: 300px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="logo"> | |
| <i class="fa-solid fa-bicycle"></i> | |
| <span>PeliCycle</span> | |
| </div> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link">Built with anycoder</a> | |
| </header> | |
| <main> | |
| <!-- SVG Canvas --> | |
| <div class="canvas-wrapper" id="canvasContainer"> | |
| <svg viewBox="0 0 800 600" xmlns="http://www.w3.org/2000/svg" id="pelicanSvg"> | |
| <defs> | |
| <linearGradient id="skyGradient" x1="0%" y1="0%" x2="0%" y2="100%"> | |
| <stop offset="0%" style="stop-color:#87CEEB;stop-opacity:1" /> | |
| <stop offset="100%" style="stop-color:#E0F7FA;stop-opacity:1" /> | |
| </linearGradient> | |
| </defs> | |
| <!-- Background --> | |
| <rect width="800" height="600" fill="url(#skyGradient)" id="bgRect"/> | |
| <!-- Sun --> | |
| <circle cx="700" cy="80" r="50" fill="#FFD700" opacity="0.8"> | |
| <animate attributeName="opacity" values="0.8;1;0.8" dur="3s" repeatCount="indefinite" /> | |
| </circle> | |
| <!-- Clouds --> | |
| <g class="cloud-move" style="opacity: 0.8;"> | |
| <path d="M100,100 Q120,80 140,100 T180,100 T220,100 T240,120 L100,120 Z" fill="white" /> | |
| </g> | |
| <g class="cloud-move" style="animation-delay: -10s; opacity: 0.6; transform: scale(0.8);"> | |
| <path d="M500,150 Q520,130 540,150 T580,150 T620,150 T640,170 L500,170 Z" fill="white" /> | |
| </g> | |
| <!-- Ground --> | |
| <rect x="0" y="500" width="800" height="100" fill="#8BC34A" id="groundRect"/> | |
| <path d="M0,500 Q100,490 200,500 T400,500 T600,500 T800,500" fill="#8BC34A" stroke="none"/> | |
| <!-- Bicycle Group --> | |
| <g transform="translate(150, 280) scale(1.2)"> | |
| <!-- Back Wheel --> | |
| <g class="wheel-rotate" transform-origin="100 150"> | |
| <circle cx="100" cy="150" r="50" fill="none" stroke="#333" stroke-width="8" id="tireColor1"/> | |
| <circle cx="100" cy="150" r="45" fill="none" stroke="#ddd" stroke-width="2"/> | |
| <!-- Spokes --> | |
| <line x1="100" y1="100" x2="100" y2="200" stroke="#bbb" stroke-width="2"/> | |
| <line x1="50" y1="150" x2="150" y2="150" stroke="#bbb" stroke-width="2"/> | |
| <line x1="65" y1="115" x2="135" y2="185" stroke="#bbb" stroke-width="2"/> | |
| <line x1="65" y1="185" x2="135" y2="115" stroke="#bbb" stroke-width="2"/> | |
| </g> | |
| <!-- Front Wheel --> | |
| <g class="wheel-rotate" transform-origin="350 150"> | |
| <circle cx="350" cy="150" r="50" fill="none" stroke="#333" stroke-width="8" id="tireColor2"/> | |
| <circle cx="350" cy="150" r="45" fill="none" stroke="#ddd" stroke-width="2"/> | |
| <!-- Spokes --> | |
| <line x1="350" y1="100" x2="350" y2="200" stroke="#bbb" stroke-width="2"/> | |
| <line x1="300" y1="150" x2="400" y2="150" stroke="#bbb" stroke-width="2"/> | |
| <line x1="315" y1="115" x2="385" y2="185" stroke="#bbb" stroke-width="2"/> | |
| <line x1="315" y1="185" x2="385" y2="115" stroke="#bbb" stroke-width="2"/> | |
| </g> | |
| <!-- Frame --> | |
| <g id="bikeFrame" stroke="#ff6b6b" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" fill="none"> | |
| <path d="M100,150 L180,50 L320,50 L350,150 L180,150 L100,150" /> <!-- Main Triangle + Rear --> | |
| <line x1="180" y1="50" x2="180" y2="150" /> <!-- Seat tube --> | |
| <line x1="320" y1="50" x2="340" y2="20" /> <!-- Handlebar stem --> | |
| </g> | |
| <!-- Seat --> | |
| <path d="M160,40 L200,40 L205,45 L190,55 L160,40" fill="#333" stroke="none"/> | |
| <!-- Handlebars --> | |
| <path d="M320,20 Q340,20 350,30" fill="none" stroke="#ccc" stroke-width="6" stroke-linecap="round"/> | |
| <circle cx="350" cy="30" r="5" fill="#333"/> | |
| <!-- Pedals Center --> | |
| <circle cx="180" cy="150" r="10" fill="#555"/> | |
| <!-- Right Leg (Behind) --> | |
| <g class="leg-pedal-r"> | |
| <path d="M200,90 Q190,120 180,150" stroke="#FF9800" stroke-width="6" fill="none" stroke-linecap="round"/> | |
| <ellipse cx="180" cy="150" rx="10" ry="5" fill="#FF9800"/> | |
| </g> | |
| <!-- The Pelican --> | |
| <g class="pelican-bounce"> | |
| <!-- Tail --> | |
| <path d="M130,80 Q110,90 130,100 L150,90 Z" fill="white"/> | |
| <!-- Body --> | |
| <ellipse cx="180" cy="80" rx="40" ry="35" fill="white"/> | |
| <!-- Neck --> | |
| <path d="M200,60 Q220,40 220,20 L200,20 Q190,40 180,60 Z" fill="white"/> | |
| <!-- Head --> | |
| <circle cx="215" cy="15" r="20" fill="white"/> | |
| <!-- Eye --> | |
| <circle cx="220" cy="10" r="3" fill="black"/> | |
| <circle cx="221" cy="9" r="1" fill="white"/> | |
| <!-- Beak (Upper) --> | |
| <path d="M230,5 Q260,5 290,15 L230,25 Z" fill="#FFB74D"/> | |
| <!-- Beak (Pouch) --> | |
| <path d="M230,25 Q260,60 280,25 L230,25" fill="#FFA726" stroke="#F57C00" stroke-width="1"/> | |
| <!-- Wing --> | |
| <path d="M160,70 Q190,60 210,80 Q180,110 160,90 Z" fill="#f0f0f0" stroke="#e0e0e0" stroke-width="1"> | |
| <animateTransform attributeName="transform" type="rotate" values="0 160 70; 5 160 70; 0 160 70" dur="0.5s" repeatCount="indefinite"/> | |
| </path> | |
| <!-- Hat (Optional accessory) --> | |
| <path d="M200,5 L230,5 L230,0 L200,0 Z" fill="#333"/> | |
| <rect x="205" y="-15" width="20" height="15" fill="#333"/> | |
| </g> | |
| <!-- Left Leg (Front) --> | |
| <g class="leg-pedal-l"> | |
| <!-- Thigh to Pedal --> | |
| <path d="M190,100 Q200,120 180,150" stroke="#FF9800" stroke-width="6" fill="none" stroke-linecap="round"/> | |
| <!-- Foot --> | |
| <ellipse cx="180" cy="150" rx="12" ry="6" fill="#FF9800" transform="rotate(-10 180 150)"/> | |
| </g> | |
| <!-- Wing holding handlebar --> | |
| <path d="M200,70 Q280,80 345,30" stroke="white" stroke-width="8" fill="none" stroke-linecap="round"/> | |
| </g> | |
| </svg> | |
| </div> | |
| <!-- Controls --> | |
| <div class="controls-wrapper"> | |
| <h2><i class="fa-solid fa-sliders"></i> Customize</h2> | |
| <div class="control-group"> | |
| <label>Bike Color</label> | |
| <input type="color" id="bikeColor" value="#ff6b6b"> | |
| </div> | |
| <div class="control-group"> | |
| <label>Pelican Beak Color</label> | |
| <input type="color" id="beakColor" value="#FFA726"> | |
| </div> | |
| <div class="control-group"> | |
| <label>Cycling Speed</label> | |
| <input type="range" id="speedControl" min="0.1" max="5" step="0.1" value="2"> | |
| </div> | |
| <div class="control-group"> | |
| <label>Time of Day</label> | |
| <button class="btn btn-secondary" id="toggleTheme"> | |
| <i class="fa-solid fa-moon"></i> Toggle Night Mode | |
| </button> | |
| </div> | |
| <div style="margin-top: auto;"> | |
| <button class="btn btn-primary" style="width: 100%;" id="downloadBtn"> | |
| <i class="fa-solid fa-download"></i> Download SVG | |
| </button> | |
| </div> | |
| </div> | |
| </main> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const bikeColorInput = document.getElementById('bikeColor'); | |
| const beakColorInput = document.getElementById('beakColor'); | |
| const speedInput = document.getElementById('speedControl'); | |
| const themeBtn = document.getElementById('toggleTheme'); | |
| const downloadBtn = document.getElementById('downloadBtn'); | |
| const bikeFrame = document.getElementById('bikeFrame'); | |
| const pelicanBeak = document.querySelector('path[fill="#FFA726"]'); // Pouch | |
| const pelicanBeakTop = document.querySelector('path[fill="#FFB74D"]'); // Top | |
| const svg = document.getElementById('pelicanSvg'); | |
| // Animation Elements | |
| const wheels = document.querySelectorAll('.wheel-rotate'); | |
| const legsL = document.querySelectorAll('.leg-pedal-l'); | |
| const legsR = document.querySelectorAll('.leg-pedal-r'); | |
| const clouds = document.querySelectorAll('.cloud-move'); | |
| // 1. Update Bike Color | |
| bikeColorInput.addEventListener('input', (e) => { | |
| bikeFrame.setAttribute('stroke', e.target.value); | |
| }); | |
| // 2. Update Beak Color | |
| beakColorInput.addEventListener('input', (e) => { | |
| pelicanBeak.setAttribute('fill', e.target.value); | |
| // Make the top part slightly lighter | |
| pelicanBeakTop.setAttribute('fill', adjustColor(e.target.value, 40)); | |
| }); | |
| // 3. Speed Control | |
| speedInput.addEventListener('input', (e) => { | |
| // Invert logic: Higher value = lower duration (faster) | |
| // Base is 2s. | |
| // If value is 5 (fast), duration should be 0.4s | |
| // If value is 0.1 (slow), duration should be 10s | |
| const val = parseFloat(e.target.value); | |
| const duration = (4 / val) + 's'; | |
| wheels.forEach(el => el.style.animationDuration = duration); | |
| legsL.forEach(el => el.style.animationDuration = duration); | |
| legsR.forEach(el => el.style.animationDuration = duration); | |
| // Clouds move relative to speed | |
| clouds.forEach(el => el.style.animationDuration = (40 / val) + 's'); | |
| }); | |
| // 4. Theme Toggle | |
| let isNight = false; | |
| themeBtn.addEventListener('click', () => { | |
| isNight = !isNight; | |
| const skyGradient = document.getElementById('skyGradient'); | |
| const sun = document.querySelector('circle[fill="#FFD700"]'); | |
| const stops = skyGradient.getElementsByTagName('stop'); | |
| const ground = document.getElementById('groundRect'); | |
| const groundPath = document.querySelector('path[fill="#8BC34A"]'); | |
| if (isNight) { | |
| stops[0].style.stopColor = "#0f2027"; | |
| stops[1].style.stopColor = "#203a43"; | |
| sun.setAttribute('fill', '#F4F6F0'); // Moon color | |
| sun.setAttribute('opacity', '0.9'); | |
| ground.setAttribute('fill', '#2d3436'); | |
| groundPath.setAttribute('fill', '#2d3436'); | |
| themeBtn.innerHTML = '<i class="fa-solid fa-sun"></i> Toggle Day Mode'; | |
| } else { | |
| stops[0].style.stopColor = "#87CEEB"; | |
| stops[1].style.stopColor = "#E0F7FA"; | |
| sun.setAttribute('fill', '#FFD700'); | |
| ground.setAttribute('fill', '#8BC34A'); | |
| groundPath.setAttribute('fill', '#8BC34A'); | |
| themeBtn.innerHTML = '<i class="fa-solid fa-moon"></i> Toggle Night Mode'; | |
| } | |
| }); | |
| // 5. Download SVG | |
| downloadBtn.addEventListener('click', () => { | |
| const svgData = new XMLSerializer().serializeToString(svg); | |
| const blob = new Blob([svgData], {type: 'image/svg+xml;charset=utf-8'}); | |
| const url = URL.createObjectURL(blob); | |
| const link = document.createElement('a'); | |
| link.href = url; | |
| link.download = 'pelican-cyclist.svg'; | |
| document.body.appendChild(link); | |
| link.click(); | |
| document.body.removeChild(link); | |
| }); | |
| // Utility: Lighten color for beak shading | |
| function adjustColor(color, amount) { | |
| return '#' + color.replace(/^#/, '').replace(/../g, color => ('0'+Math.min(255, Math.max(0, parseInt(color, 16) + amount)).toString(16)).substr(-2)); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |