- linmao2026-09-0311778
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>鹈鹕骑自行车 · SVG 2D 动画</title> <style> :root{ --speed: 1; --spin-dur: 1s; --bounce-dur: .5s; } *{box-sizing:border-box} body{ margin:0; min-height:100vh; display:flex; flex-direction:column; align-items:center; font-family: "PingFang SC","Microsoft YaHei",system-ui,sans-serif; background:#0f172a; color:#e2e8f0; background: radial-gradient(1200px 600px at 50% -10%, #334155 0%, #0f172a 60%, #020617 100%); padding:24px 16px 40px; } h1{margin:8px 0 4px; font-size:clamp(22px,3.5vw,34px); letter-spacing:.06em} h1 span{ background:linear-gradient(90deg,#fde68a,#fb923c,#f472b6); -webkit-background-clip:text; background-clip:text; color:transparent;} p.sub{margin:0 0 16px; opacity:.7} .stage{ width:min(920px,96vw); border-radius:20px; overflow:hidden; box-shadow:0 20px 60px rgba(0,0,0,.5), 0 0 0 1px rgba(255,255,255,.08) inset; background:#87ceeb; position:relative; } svg{display:block; width:100%; height:auto} .panel{ width:min(920px,96vw); margin-top:14px; display:flex; flex-wrap:wrap; gap:12px; align-items:center; justify-content:space-between; background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.1); border-radius:14px; padding:12px 16px; backdrop-filter: blur(8px); } .controls{display:flex; gap:10px; align-items:center; flex-wrap:wrap} button{ border:0; border-radius:999px; padding:9px 18px; cursor:pointer; font-weight:700; background:#fff; color:#0f172a; transition:.2s; } button:hover{transform:translateY(-1px)} button.secondary{background:rgba(255,255,255,.14); color:#fff; border:1px solid rgba(255,255,255,.2)} input[type=range]{accent-color:#fb923c; width:160px} label{font-size:14px; opacity:.9; display:flex; gap:8px; align-items:center} .hint{font-size:13px; opacity:.6} /* ===== SVG animations ===== */ .wheel-spin{ transform-box: fill-box; transform-origin:center; animation: spin var(--spin-dur) linear infinite; } @keyframes spin{ to{transform:rotate(360deg)} } #rider-bounce{ animation: bounce var(--bounce-dur) ease-in-out infinite alternate; } @keyframes bounce{ from{transform:translateY(0)} to{transform:translateY(-5px)} } #body-bob{ animation: bodyBob var(--bounce-dur) ease-in-out infinite alternate; } @keyframes bodyBob{ from{transform:translateY(0) rotate(-1deg)} to{transform:translateY(-4px) rotate(1deg)} } #wing{ transform-box:fill-box; transform-origin: 20% 20%; animation: flap .7s ease-in-out infinite alternate; } @keyframes flap{ from{transform:rotate(-8deg)} to{transform:rotate(28deg)} } #neck-head{ animation: headBob var(--bounce-dur) ease-in-out infinite alternate; transform-box:fill-box; transform-origin:0% 100%; } @keyframes headBob{ from{transform:translateY(0) rotate(0deg)} to{transform:translateY(-3px) rotate(-2.5deg)} } #pouch{ transform-box:fill-box; transform-origin: top center; animation: pouchWobble 1s ease-in-out infinite alternate; } @keyframes pouchWobble{ from{transform:scaleY(1) skewX(0deg)} to{transform:scaleY(1.07) skewX(2deg)} } #eye-lid{ transform-box:fill-box; transform-origin:center; animation: blink 4s infinite; } @keyframes blink{ 0%,92%,100%{transform:scaleY(1)} 95%{transform:scaleY(.08)} } #scarf-tail{ transform-box:fill-box; transform-origin:right center; animation: scarfWave .6s ease-in-out infinite alternate; } @keyframes scarfWave{ from{transform:rotate(-6deg) scaleX(1)} to{transform:rotate(8deg) scaleX(1.08)} } #scarf-tail2{ animation: wave2 .6s ease-in-out infinite alternate; } @keyframes wave2{ from{transform:translateY(0)} to{transform:translateY(-4px)} } .cloud{ animation: drift linear infinite; } .cloud.c1{ animation-duration:26s } .cloud.c2{ animation-duration:38s } .cloud.c3{ animation-duration:55s } @keyframes drift{ from{transform:translateX(-140px)} to{transform:translateX(940px)} } #road-dashes{ animation: roadMove .5s linear infinite; } @keyframes roadMove{ to{ stroke-dashoffset:-40; } } .bg-scroll{ animation: bgMove 3.2s linear infinite; } .bg-scroll-fast{ animation: bgMove 1.6s linear infinite; } @keyframes bgMove{ to{transform:translateX(-200px)} } .dust{ animation: dustPuff 1s ease-out infinite; opacity:0; transform-box:fill-box; transform-origin:center; } .dust.d2{ animation-delay:.33s } .dust.d3{ animation-delay:.66s } @keyframes dustPuff{ 0%{opacity:.7; transform:translate(0,0) scale(.5)} 100%{opacity:0; transform:translate(-70px,-18px) scale(1.4)} } .speed-line{ animation: speedFlash .45s linear infinite; opacity:0 } .speed-line.s2{animation-delay:.15s} .speed-line.s3{animation-delay:.3s} @keyframes speedFlash{ 0%{opacity:0; transform:translateX(20px)} 30%{opacity:.7} 100%{opacity:0; transform:translateX(-60px)} } #front-basket{ animation: basketShake var(--bounce-dur) ease-in-out infinite alternate; transform-box:fill-box; transform-origin:top center;} @keyframes basketShake{ from{transform:rotate(-1.5deg)} to{transform:rotate(1.5deg)} } .pedal-crank{ transform-box:fill-box; transform-origin:center; animation: spin var(--spin-dur) linear infinite; } .paused *{ animation-play-state:paused !important; } /* night mode (toggle class on svg) */ svg.night #sky{ fill:url(#nightGrad) } svg.night .stars{opacity:1} .stars{opacity:0; transition:.6s} svg.night #sun{opacity:0} svg.night #moon{opacity:1} #moon{opacity:0; transition:.6s} #sun{transition:.6s} </style> </head> <body> <h1>🚲 <span>鹈鹕骑自行车</span> · SVG 2D 动画</h1> <p class="sub">纯 SVG + CSS + 少量 JS(脚踏腿部 IK 跟随)· 车轮转动 / 脚踏 / 翅膀扇动 / 围巾飘动 / 眨眼 / 沙尘</p> <div class="stage"> <svg id="scene" viewBox="0 0 900 520" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="鹈鹕骑自行车动画"> <defs> <linearGradient id="skyGrad" x1="0" y1="0" x2="0" y2="1"> <stop offset="0%" stop-color="#38bdf8"/><stop offset="55%" stop-color="#bae6fd"/><stop offset="100%" stop-color="#fef9c3"/> </linearGradient> <linearGradient id="nightGrad" x1="0" y1="0" x2="0" y2="1"> <stop offset="0%" stop-color="#020617"/><stop offset="60%" stop-color="#1e1b4b"/><stop offset="100%" stop-color="#334155"/> </linearGradient> <linearGradient id="roadGrad" x1="0" y1="0" x2="0" y2="1"> <stop offset="0%" stop-color="#64748b"/><stop offset="100%" stop-color="#334155"/> </linearGradient> <linearGradient id="bodyGrad" x1="0" y1="0" x2="0" y2="1"> <stop offset="0%" stop-color="#ffffff"/><stop offset="100%" stop-color="#e2e8f0"/> </linearGradient> <linearGradient id="beakGrad" x1="0" y1="0" x2="0" y2="1"> <stop offset="0%" stop-color="#fdba74"/><stop offset="100%" stop-color="#ea580c"/> </linearGradient> <linearGradient id="pouchGrad" x1="0" y1="0" x2="0" y2="1"> <stop offset="0%" stop-color="#ffedd5"/><stop offset="100%" stop-color="#fb923c"/> </linearGradient> <radialGradient id="sunGrad" cx="50%" cy="50%" r="50%"> <stop offset="0%" stop-color="#fefce8"/><stop offset="45%" stop-color="#fde047"/><stop offset="100%" stop-color="#f59e0b" stop-opacity=".2"/> </radialGradient> </defs> <!-- 天空 --> <rect id="sky" x="0" y="0" width="900" height="520" fill="url(#skyGrad)"/> <g class="stars" fill="white"> <circle cx="80" cy="60" r="2"/><circle cx="200" cy="40" r="1.6"/><circle cx="340" cy="80" r="2"/> <circle cx="500" cy="35" r="1.5"/><circle cx="640" cy="70" r="2"/><circle cx="780" cy="50" r="1.8"/> <circle cx="860" cy="120" r="1.4"/><circle cx="120" cy="140" r="1.3"/><circle cx="420" cy="120" r="1.2"/> </g> <!-- 太阳 / 月亮 --> <g id="sun" transform="translate(750,90)"> <circle r="58" fill="url(#sunGrad)"/> <circle r="36" fill="#fde047" stroke="#f59e0b" stroke-width="3"/> </g> <g id="moon" transform="translate(750,90)"> <circle r="30" fill="#e2e8f0"/><circle cx="10" cy="-6" r="6" fill="#94a3b8" opacity=".6"/><circle cx="-8" cy="8" r="4" fill="#94a3b8" opacity=".5"/> </g> <!-- 云 --> <g class="cloud c1" transform="translate(0,70)"> <g fill="white" opacity=".95"><ellipse cx="0" cy="0" rx="42" ry="22"/><ellipse cx="35" cy="-10" rx="30" ry="20"/><ellipse cx="-35" cy="-6" rx="26" ry="16"/></g> </g> <g class="cloud c2" transform="translate(0,130)"> <g fill="white" opacity=".85"><ellipse cx="0" cy="0" rx="52" ry="20"/><ellipse cx="40" cy="-12" rx="28" ry="18"/></g> </g> <g class="cloud c3" transform="translate(0,45)"> <g fill="white" opacity=".7"><ellipse cx="0" cy="0" rx="36" ry="16"/><ellipse cx="28" cy="-8" rx="22" ry="14"/></g> </g> <!-- 远山 --> <path d="M0 340 L120 220 L210 300 L320 200 L430 310 L540 230 L650 320 L760 240 L900 330 L900 420 L0 420 Z" fill="#7dd3fc" opacity=".55"/> <path d="M0 360 L150 270 L280 340 L420 260 L580 350 L720 280 L900 360 L900 430 L0 430 Z" fill="#0284c7" opacity=".35"/> <!-- 飞鸟 --> <g stroke="#334155" stroke-width="2.5" fill="none" stroke-linecap="round" opacity=".6"> <path d="M200 120 q8 -8 16 0 q8 -8 16 0"><animate attributeName="d" dur="1.2s" repeatCount="indefinite" values="M200 120 q8 -8 16 0 q8 -8 16 0;M200 125 q8 -2 16 0 q8 -2 16 0;M200 120 q8 -8 16 0 q8 -8 16 0"/></path> <path d="M260 100 q6 -6 12 0 q6 -6 12 0"><animate attributeName="d" dur="1s" repeatCount="indefinite" values="M260 100 q6 -6 12 0 q6 -6 12 0;M260 105 q6 -1 12 0 q6 -1 12 0;M260 100 q6 -6 12 0 q6 -6 12 0"/></path> </g> <!-- 背景树(滚动) --> <g class="bg-scroll" opacity=".9"> <g id="trees-pattern"> <!-- repeat every 200px --> <g transform="translate(0,0)"> <rect x="40" y="320" width="14" height="60" rx="4" fill="#92400e"/> <circle cx="47" cy="300" r="32" fill="#16a34a"/><circle cx="25" cy="315" r="20" fill="#22c55e"/> </g> <g transform="translate(200,0)"> <rect x="40" y="320" width="14" height="60" rx="4" fill="#92400e"/> <circle cx="47" cy="300" r="32" fill="#15803d"/><circle cx="70" cy="315" r="18" fill="#22c55e"/> </g> <g transform="translate(400,0)"> <rect x="40" y="320" width="14" height="60" rx="4" fill="#92400e"/> <circle cx="47" cy="300" r="32" fill="#16a34a"/><circle cx="25" cy="315" r="20" fill="#22c55e"/> </g> <g transform="translate(600,0)"> <rect x="40" y="320" width="14" height="60" rx="4" fill="#92400e"/> <circle cx="47" cy="300" r="32" fill="#15803d"/><circle cx="70" cy="315" r="18" fill="#22c55e"/> </g> <g transform="translate(800,0)"> <rect x="40" y="320" width="14" height="60" rx="4" fill="#92400e"/> <circle cx="47" cy="300" r="32" fill="#16a34a"/><circle cx="25" cy="315" r="20" fill="#22c55e"/> </g> <g transform="translate(1000,0)"> <rect x="40" y="320" width="14" height="60" rx="4" fill="#92400e"/> <circle cx="47" cy="300" r="32" fill="#15803d"/> </g> </g> </g> <!-- 地面 + 公路 --> <rect x="0" y="380" width="900" height="140" fill="#86efac"/> <rect x="0" y="400" width="900" height="90" fill="url(#roadGrad)"/> <rect x="0" y="400" width="900" height="8" fill="#e2e8f0"/> <g class="bg-scroll-fast"> <g fill="#22c55e"> <rect x="0" y="382" width="80" height="10" rx="5" opacity=".6"/><rect x="200" y="382" width="80" height="10" rx="5" opacity=".6"/> <rect x="400" y="382" width="80" height="10" rx="5" opacity=".6"/><rect x="600" y="382" width="80" height="10" rx="5" opacity=".6"/> <rect x="800" y="382" width="80" height="10" rx="5" opacity=".6"/><rect x="1000" y="382" width="80" height="10" rx="5" opacity=".6"/> </g> </g> <line id="road-dashes" x1="0" y1="448" x2="900" y2="448" stroke="#fde047" stroke-width="8" stroke-dasharray="28 12" stroke-linecap="round"/> <!-- 速度线 --> <g stroke="white" stroke-width="5" stroke-linecap="round"> <line class="speed-line" x1="220" y1="300" x2="150" y2="300"/> <line class="speed-line s2" x1="240" y1="340" x2="150" y2="340"/> <line class="speed-line s3" x1="220" y1="260" x2="160" y2="260"/> </g> <!-- ============ 鹈鹕 + 自行车 ============ --> <g id="rider-bounce"> <!-- 阴影 --> <ellipse cx="410" cy="476" rx="140" ry="12" fill="black" opacity=".18"/> <!-- 后轮 --> <g transform="translate(320,420)"> <circle r="52" fill="#1e293b" /><circle r="44" fill="#f8fafc"/> <g class="wheel-spin"> <g stroke="#0f172a" stroke-width="3"> <line x1="-40" y1="0" x2="40" y2="0"/><line x1="0" y1="-40" x2="0" y2="40"/> <line x1="-28" y1="-28" x2="28" y2="28"/><line x1="-28" y1="28" x2="28" y2="-28"/> </g> <circle r="8" fill="#fb923c" stroke="#0f172a" stroke-width="2"/> </g> <circle r="52" fill="none" stroke="#0f172a" stroke-width="6"/> </g> <!-- 前轮 --> <g transform="translate(520,420)"> <circle r="52" fill="#1e293b"/><circle r="44" fill="#f8fafc"/> <g class="wheel-spin"> <g stroke="#0f172a" stroke-width="3"> <line x1="-40" y1="0" x2="40" y2="0"/><line x1="0" y1="-40" x2="0" y2="40"/> <line x1="-28" y1="-28" x2="28" y2="28"/><line x1="-28" y1="28" x2="28" y2="-28"/> </g> <circle r="8" fill="#fb923c" stroke="#0f172a" stroke-width="2"/> </g> <circle r="52" fill="none" stroke="#0f172a" stroke-width="6"/> <!-- 挡泥板 --> <path d="M-54 -8 A 56 56 0 0 1 30 -48" fill="none" stroke="#ef4444" stroke-width="7" stroke-linecap="round"/> </g> <!-- 车架 --> <g stroke-linecap="round" stroke-linejoin="round" fill="none"> <line x1="320" y1="420" x2="405" y2="418" stroke="#ef4444" stroke-width="9"/> <!-- 后下叉 --> <line x1="320" y1="420" x2="375" y2="330" stroke="#ef4444" stroke-width="9"/> <!-- 立管 --> <line x1="375" y1="330" x2="405" y2="418" stroke="#ef4444" stroke-width="8"/> <line x1="405" y1="418" x2="505" y2="330" stroke="#dc2626" stroke-width="9"/> <!-- 下管 --> <line x1="375" y1="330" x2="505" y2="330" stroke="#ef4444" stroke-width="8"/> <!-- 上管 --> <line x1="505" y1="330" x2="520" y2="420" stroke="#dc2626" stroke-width="9"/> <!-- 前叉 --> <line x1="505" y1="330" x2="530" y2="305" stroke="#1e293b" stroke-width="8"/> <!-- 车把立 --> </g> <!-- 座垫 & 车把 --> <rect x="348" y="312" width="54" height="16" rx="8" fill="#1e293b"/> <rect x="368" y="326" width="10" height="12" fill="#94a3b8"/> <g transform="translate(530,305)"> <rect x="-8" y="-8" width="36" height="12" rx="6" fill="#1e293b"/> <circle cx="26" cy="-2" r="4" fill="#fde047"/> </g> <!-- 车灯 --> <g transform="translate(534,332)"><circle r="9" fill="#fef08a" stroke="#1e293b" stroke-width="2.5"/><circle r="3.5" fill="#facc15"/></g> <!-- 前车篮 + 鱼! --> <g id="front-basket" transform="translate(545,340)"> <path d="M0 0 L56 0 L50 36 L6 36 Z" fill="#d6a35c" stroke="#92400e" stroke-width="3" stroke-linejoin="round"/> <line x1="8" y1="12" x2="52" y2="12" stroke="#92400e" stroke-width="2" opacity=".6"/> <line x1="10" y1="24" x2="51" y2="24" stroke="#92400e" stroke-width="2" opacity=".6"/> <!-- 鱼尾巴露出 --> <g transform="translate(28,-6) rotate(-12)"> <ellipse cx="0" cy="0" rx="16" ry="8" fill="#38bdf8" stroke="#075985" stroke-width="2"/> <path d="M14 0 L26 -9 L26 9 Z" fill="#0284c7"/> <circle cx="-7" cy="-1" r="2" fill="#0f172a"/> </g> </g> <!-- 中轴 & 脚踏曲柄 (JS 驱动旋转) --> <g transform="translate(405,418)"> <circle r="10" fill="#1e293b"/> <g id="crank"> <line id="crank-arm1" x1="0" y1="0" x2="0" y2="0" stroke="#1e293b" stroke-width="6" stroke-linecap="round"/> <line id="crank-arm2" x1="0" y1="0" x2="0" y2="0" stroke="#1e293b" stroke-width="6" stroke-linecap="round"/> <rect id="pedal1" x="-12" y="-5" width="24" height="10" rx="3" fill="#0f172a"/> <rect id="pedal2" x="-12" y="-5" width="24" height="10" rx="3" fill="#0f172a"/> </g> </g> <!-- 腿 (JS 更新 path d) --> <path id="leg-far" d="" fill="none" stroke="#f59e0b" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" opacity=".7"/> <path id="leg-near" d="" fill="none" stroke="#ea580c" stroke-width="11" stroke-linecap="round" stroke-linejoin="round"/> <!-- ===== 鹈鹕身体 ===== --> <g id="body-bob"> <!-- 尾巴 --> <path d="M300 300 L262 288 L268 306 L258 314 L300 320 Z" fill="#cbd5e1" stroke="#64748b" stroke-width="2" stroke-linejoin="round"/> <!-- 身体 --> <ellipse cx="365" cy="280" rx="72" ry="52" fill="url(#bodyGrad)" stroke="#0f172a" stroke-width="3.5"/> <ellipse cx="350" cy="300" rx="40" ry="26" fill="#e2e8f0" opacity=".8"/> <!-- 翅膀 --> <g id="wing" transform="translate(360,270)"> <path d="M0 0 C -40 -18 -78 -12 -96 14 C -70 22 -38 22 0 12 Z" fill="#f1f5f9" stroke="#0f172a" stroke-width="3" stroke-linejoin="round"/> <path d="M-10 2 C -36 -6 -62 -4 -78 8" fill="none" stroke="#94a3b8" stroke-width="2.5" stroke-linecap="round"/> <path d="M-8 8 C -30 4 -52 6 -64 14" fill="none" stroke="#94a3b8" stroke-width="2" stroke-linecap="round"/> </g> <!-- 围巾 --> <g transform="translate(318,232)"> <rect x="-26" y="-12" width="40" height="24" rx="10" fill="#ef4444"/> <rect x="-26" y="-12" width="12" height="24" fill="#b91c1c" opacity=".5"/> <g id="scarf-tail"> <path id="scarf-tail2" d="M-26 0 C -60 -14 -84 -8 -108 6 C -86 12 -60 16 -26 12 Z" fill="#ef4444" stroke="#991b1b" stroke-width="2"/> <line x1="-92" y1="-2" x2="-92" y2="10" stroke="#fecaca" stroke-width="3"/> <line x1="-82" y1="-2" x2="-82" y2="11" stroke="#fecaca" stroke-width="3"/> </g> </g> <!-- 脖子 + 头 --> <g id="neck-head"> <path d="M415 250 C 445 230 455 200 448 170" fill="none" stroke="white" stroke-width="30" stroke-linecap="round"/> <path d="M415 250 C 445 230 455 200 448 170" fill="none" stroke="#0f172a" stroke-width="33" stroke-linecap="round" opacity=".08"/> <path d="M415 250 C 445 230 455 200 448 170" fill="none" stroke="#cbd5e1" stroke-width="30" stroke-linecap="round" stroke-dasharray="0" opacity=".35"/> <!-- 头 --> <ellipse cx="452" cy="152" rx="34" ry="28" fill="white" stroke="#0f172a" stroke-width="3"/> <!-- 头顶毛 --> <path d="M428 132 q6 -14 12 0 q6 -14 12 0 q6 -12 12 -2" fill="none" stroke="#0f172a" stroke-width="3" stroke-linecap="round"/> <!-- 眼睛 --> <g transform="translate(462,146)"> <circle r="10" fill="white" stroke="#0f172a" stroke-width="2.5"/> <circle cx="2.5" cy="1" r="5" fill="#0f172a"/> <circle cx="4" cy="-0.5" r="1.8" fill="white"/> <rect id="eye-lid" x="-11" y="-11" width="22" height="22" rx="11" fill="white"/> </g> <!-- 腮红 --> <ellipse cx="442" cy="162" rx="7" ry="4.5" fill="#fda4af" opacity=".8"/> <!-- 喙 --> <g transform="translate(480,150)"> <path d="M0 -8 L110 -2 L0 8 Z" fill="url(#beakGrad)" stroke="#9a3412" stroke-width="2.5" stroke-linejoin="round"/> <line x1="6" y1="1" x2="102" y2="1" stroke="#9a3412" stroke-width="1.6" opacity=".7"/> <circle cx="104" cy="-1" r="3" fill="#7c2d12"/> <!-- 喉囊 --> <path id="pouch" d="M4 7 C 40 14 80 12 104 0 C 88 26 40 34 8 22 Z" fill="url(#pouchGrad)" stroke="#9a3412" stroke-width="2.5" stroke-linejoin="round"/> </g> <!-- 帽子? 小头盔 --> <g transform="translate(452,122)"> <path d="M-24 0 A 24 16 0 0 1 24 0 Z" fill="#ef4444" stroke="#7f1d1d" stroke-width="2.5"/> <rect x="-26" y="-2" width="52" height="7" rx="3.5" fill="#7f1d1d"/> <circle cx="0" cy="-18" r="4" fill="#fde047" stroke="#7f1d1d" stroke-width="2"/> </g> </g> </g> <!-- 尘土 --> <g fill="#d6c7a8"> <circle class="dust" cx="270" cy="440" r="9"/> <circle class="dust d2" cx="270" cy="450" r="7"/> <circle class="dust d3" cx="270" cy="435" r="6"/> </g> </g> </svg> </div> <div class="panel"> <div class="controls"> <button id="btn-pause">⏸ 暂停</button> <button id="btn-night" class="secondary">🌙 夜晚模式</button> <button id="btn-ring" class="secondary">🔔 按铃铛</button> <label>🚴 速度 <input id="speed" type="range" min="0.2" max="2.5" step="0.1" value="1" /> <span id="speed-val">1.0x</span></label> </div> <div class="hint">小技巧:拖动速度滑杆,车轮 / 脚踏 / 背景会一起变速 · 腿部是 JS 实时 IK 跟随脚踏</div> </div> <script> const svg = document.getElementById('scene'); const speedInput = document.getElementById('speed'); const speedVal = document.getElementById('speed-val'); const btnPause = document.getElementById('btn-pause'); const btnNight = document.getElementById('btn-night'); const btnRing = document.getElementById('btn-ring'); let speed = 1, paused = false, crankAngle = 0; // 速度 -> CSS 变量 function applySpeed(){ document.documentElement.style.setProperty('--spin-dur', (1/speed)+'s'); document.documentElement.style.setProperty('--bounce-dur', (0.5/speed)+'s'); document.querySelectorAll('.bg-scroll').forEach(e=>e.style.animationDuration=(3.2/speed)+'s'); document.querySelectorAll('.bg-scroll-fast').forEach(e=>e.style.animationDuration=(1.6/speed)+'s'); document.getElementById('road-dashes').style.animationDuration=(0.5/speed)+'s'; speedVal.textContent = speed.toFixed(1)+'x'; } speedInput.addEventListener('input', e=>{ speed=parseFloat(e.target.value); applySpeed(); }); applySpeed(); btnPause.addEventListener('click', ()=>{ paused=!paused; svg.classList.toggle('paused', paused); btnPause.textContent = paused ? '▶ 继续' : '⏸ 暂停'; }); btnNight.addEventListener('click', ()=>{ const night = svg.classList.toggle('night'); btnNight.textContent = night ? '☀️ 白天模式' : '🌙 夜晚模式'; }); btnRing.addEventListener('click', ()=>{ // 铃铛:车把小黄点跳一下 + 响声(WebAudio) try{ const ctx = new (window.AudioContext||window.webkitAudioContext)(); [880,1174].forEach((f,i)=>{ const o=ctx.createOscillator(), g=ctx.createGain(); o.type='sine'; o.frequency.value=f; g.gain.setValueAtTime(0.25, ctx.currentTime+i*0.12); g.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime+i*0.12+0.4); o.connect(g).connect(ctx.destination); o.start(ctx.currentTime+i*0.12); o.stop(ctx.currentTime+i*0.12+0.45); }); }catch(e){} btnRing.textContent='🔔 叮铃铃~'; setTimeout(()=>btnRing.textContent='🔔 按铃铛',900); }); // ---- 腿部跟随脚踏 (每帧更新) ---- const BB = {x:405, y:418}; // 五通中轴 (SVG坐标) const CR = 22; // 曲柄半径 const hipNear = {x:385, y:280}; // 近侧髋 const hipFar = {x:368, y:282}; // 远侧髋 const crank = document.getElementById('crank'); const arm1 = document.getElementById('crank-arm1'); const arm2 = document.getElementById('crank-arm2'); const ped1 = document.getElementById('pedal1'); const ped2 = document.getElementById('pedal2'); const legNear = document.getElementById('leg-near'); const legFar = document.getElementById('leg-far'); function kneePos(hip, foot, bend){ const mx=(hip.x+foot.x)/2, my=(hip.y+foot.y)/2; // 膝盖向前凸 const dx=foot.x-hip.x, dy=foot.y-hip.y; const len=Math.hypot(dx,dy)||1; const nx=-dy/len, ny=dx/len; return {x:mx+nx*bend, y:my+ny*bend}; } let last=performance.now(); function tick(now){ const dt=Math.min(0.05,(now-last)/1000); last=now; if(!paused){ crankAngle += dt * Math.PI*2 * speed; // 1圈/秒 * speed const a1=crankAngle, a2=crankAngle+Math.PI; const f1={x:BB.x+Math.cos(a1)*CR, y:BB.y+Math.sin(a1)*CR}; const f2={x:BB.x+Math.cos(a2)*CR, y:BB.y+Math.sin(a2)*CR}; arm1.setAttribute('x2', (Math.cos(a1)*CR).toFixed(1)); arm1.setAttribute('y2', (Math.sin(a1)*CR).toFixed(1)); arm2.setAttribute('x2', (Math.cos(a2)*CR).toFixed(1)); arm2.setAttribute('y2', (Math.sin(a2)*CR).toFixed(1)); ped1.setAttribute('x', (Math.cos(a1)*CR-12).toFixed(1)); ped1.setAttribute('y', (Math.sin(a1)*CR-5).toFixed(1)); ped2.setAttribute('x', (Math.cos(a2)*CR-12).toFixed(1)); ped2.setAttribute('y', (Math.sin(a2)*CR-5).toFixed(1)); // 腿:髋 -> 膝 -> 脚 const k1=kneePos(hipNear,f1,18), k2=kneePos(hipFar,f2,16); legNear.setAttribute('d', `M${hipNear.x} ${hipNear.y} L${k1.x.toFixed(1)} ${k1.y.toFixed(1)} L${f1.x.toFixed(1)} ${f1.y.toFixed(1)}`); legFar.setAttribute('d', `M${hipFar.x} ${hipFar.y} L${k2.x.toFixed(1)} ${k2.y.toFixed(1)} L${f2.x.toFixed(1)} ${f2.y.toFixed(1)}`); // 脚蹼 // (用 pedal 本体 + 腿末端即脚,足够可爱) } requestAnimationFrame(tick); } requestAnimationFrame(tick); </script> </body> </html> ```提示词: `创建一个HTML,内容是SVG绘制一个鹈鹕骑自行车的2D动画` 用的opencode里的免费的,思考强度xhigh 主楼 - heds2026-09-045074
怎么感觉一股gemini的味道呢
- starless2026-09-0420278
AA 61 分,就这水平?
- xzcokw2026-09-0419504
看起来感觉不错哦
- MU2026-09-0412733
opencode zen muse-spark-1.3-contributor-free 魔方:魔方纸上实验室 — RUBIK ATELIER
- 第一个mt2026-09-0417991
跑分没输过实测没赢过 ^-^
- person2026-09-045661
- sczerg2026-09-045298
好像很便宜,OPENROUTER有数据训练版,历史最低价,也是惊到我了。
- kinda662026-09-046037
讲道理,gemini的鹈鹕画的比他好看多了。
