Muse Spark 1.3 鹈鹕骑自行车

linmao 2026-09-03 18:41 1

<!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


最新回复 (8)
  • heds 09-04 11:41
    1

    怎么感觉一股gemini的味道呢

  • starless 09-04 11:42
    2

    AA 61 分,就这水平?

  • xzcokw 09-04 11:43
    3

    看起来感觉不错哦

  • MU 09-04 11:43
    4

    opencode zen muse-spark-1.3-contributor-free 魔方:魔方纸上实验室 — RUBIK ATELIER

  • 第一个mt 09-04 11:47
    5

    跑分没输过实测没赢过 ^-^

  • person 09-04 11:53
    6

    还行吧,试了下糖果问题也能做对。至少是dsv4-0731,glm-5.3-flash这级别的,能用


  • sczerg 09-04 11:56
    7

    好像很便宜,OPENROUTER有数据训练版,历史最低价,也是惊到我了。

  • kinda66 09-04 16:05
    8

    讲道理,gemini的鹈鹕画的比他好看多了。

* 帖子来源Linux.do
返回