提示词:创建一个HTML,内容是SVG绘制一个鹈鹕骑自行车的2D动画,不查看任何其他文件
模型:deepseek v4.1 1017(workbuddy国际版反代)
工具:claude code
思考模式:max
以下为生成代码,其中调用了playwright工具
用时大约15-25分钟左右
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>鹈鹕骑自行车</title>
<style>
html, body { margin: 0; height: 100%; background: #0d1220; overflow: hidden; }
#stage { display: block; width: 100vw; height: 100vh; }
</style>
</head>
<body>
<svg id="stage" viewBox="0 0 1120 640" preserveAspectRatio="xMidYMid slice"
xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- ===== 渐变 ===== -->
<linearGradient id="sky" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#9ed6ee"/>
<stop offset="0.55" stop-color="#d9edf5"/>
<stop offset="1" stop-color="#f7f0e1"/>
</linearGradient>
<radialGradient id="sunGlow">
<stop offset="0" stop-color="#fff8d6" stop-opacity="0.95"/>
<stop offset="0.45" stop-color="#ffeeb0" stop-opacity="0.42"/>
<stop offset="1" stop-color="#ffeeb0" stop-opacity="0"/>
</radialGradient>
<linearGradient id="grass" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#9ad3ab"/>
<stop offset="1" stop-color="#63a37e"/>
</linearGradient>
<linearGradient id="road" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#d5cbb7"/>
<stop offset="1" stop-color="#a3977f"/>
</linearGradient>
<linearGradient id="bodyGrad" x1="0" y1="0" x2="0.25" y2="1">
<stop offset="0" stop-color="#fffdf8"/>
<stop offset="0.7" stop-color="#f4eee2"/>
<stop offset="1" stop-color="#e6ddcd"/>
</linearGradient>
<linearGradient id="wingGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#fffdf8"/>
<stop offset="1" stop-color="#e9e1d1"/>
</linearGradient>
<!-- ===== 可复用形状 ===== -->
<path id="hillFarPath" d="" fill="#b7d9c7"/>
<path id="hillNearPath" d="" fill="#8cc2a6"/>
<rect id="dash" width="72" height="8" rx="4" fill="#f6f0e0" opacity="0.8"/>
<g id="spokes" stroke="#c9ced8" stroke-width="2.2" stroke-linecap="round">
<line x1="0" y1="-64" x2="0" y2="64"/>
<line x1="0" y1="-64" x2="0" y2="64" transform="rotate(30)"/>
<line x1="0" y1="-64" x2="0" y2="64" transform="rotate(60)"/>
<line x1="0" y1="-64" x2="0" y2="64" transform="rotate(90)"/>
<line x1="0" y1="-64" x2="0" y2="64" transform="rotate(120)"/>
<line x1="0" y1="-64" x2="0" y2="64" transform="rotate(150)"/>
</g>
<g id="bush">
<circle cx="0" cy="-8" r="13"/>
<circle cx="-14" cy="2" r="12"/>
<circle cx="14" cy="2" r="12"/>
<circle cx="0" cy="4" r="14"/>
</g>
</defs>
<!-- ================= 背景(矩形外扩,宽屏裁切不露底) ================= -->
<rect x="-600" y="-500" width="2100" height="1000" fill="url(#sky)"/>
<circle cx="748" cy="112" r="130" fill="url(#sunGlow)"/>
<circle cx="748" cy="112" r="42" fill="#fff7d0"/>
<!-- 云 -->
<g id="cloudLayer" fill="#ffffff" opacity="0.88">
<g class="cloud" data-x="120" data-y="82" data-v="9" data-s="1">
<ellipse cx="0" cy="0" rx="56" ry="20"/>
<circle cx="-26" cy="-12" r="21"/>
<circle cx="8" cy="-19" r="27"/>
<circle cx="40" cy="-6" r="18"/>
</g>
<g class="cloud" data-x="430" data-y="136" data-v="6.5" data-s="0.72">
<ellipse cx="0" cy="0" rx="56" ry="20"/>
<circle cx="-26" cy="-12" r="21"/>
<circle cx="8" cy="-19" r="27"/>
<circle cx="40" cy="-6" r="18"/>
</g>
<g class="cloud" data-x="720" data-y="58" data-v="11.5" data-s="1.18">
<ellipse cx="0" cy="0" rx="56" ry="20"/>
<circle cx="-26" cy="-12" r="21"/>
<circle cx="8" cy="-19" r="27"/>
<circle cx="40" cy="-6" r="18"/>
</g>
<g class="cloud" data-x="980" data-y="150" data-v="5.5" data-s="0.6">
<ellipse cx="0" cy="0" rx="56" ry="20"/>
<circle cx="-26" cy="-12" r="21"/>
<circle cx="8" cy="-19" r="27"/>
<circle cx="40" cy="-6" r="18"/>
</g>
</g>
<!-- 远山 / 近山(视差滚动,三块拼接覆盖宽屏) -->
<g id="hillsFar">
<use href="#hillFarPath" x="-900"/>
<use href="#hillFarPath"/>
<use href="#hillFarPath" x="900"/>
</g>
<g id="hillsNear">
<use href="#hillNearPath" x="-900"/>
<use href="#hillNearPath"/>
<use href="#hillNearPath" x="900"/>
</g>
<!-- 草地与路面 -->
<rect x="-600" y="428" width="2100" height="172" fill="url(#grass)"/>
<g id="bushBand"></g>
<rect x="-600" y="528" width="2100" height="112" fill="url(#road)"/>
<line x1="-600" y1="529" x2="1500" y2="529" stroke="#c8bda8" stroke-width="3"/>
<g id="dashBand"></g>
<!-- 地面投影 -->
<ellipse cx="470" cy="534" rx="188" ry="11" fill="#3a4a3f" opacity="0.15"/>
<!-- ================= 自行车 ================= -->
<!-- 后轮 -->
<g transform="translate(340 452)">
<circle r="78" fill="none" stroke="#33333d" stroke-width="11"/>
<circle r="69" fill="none" stroke="#b9c0cc" stroke-width="2"/>
<g id="rearSpokes">
<circle r="66" fill="none" stroke="#cdd2da" stroke-width="3"/>
<use href="#spokes"/>
</g>
<circle r="8" fill="#7f8592"/>
<circle r="3.5" fill="#4b4f5a"/>
</g>
<!-- 前轮 -->
<g transform="translate(600 452)">
<circle r="78" fill="none" stroke="#33333d" stroke-width="11"/>
<circle r="69" fill="none" stroke="#b9c0cc" stroke-width="2"/>
<g id="frontSpokes">
<circle r="66" fill="none" stroke="#cdd2da" stroke-width="3"/>
<use href="#spokes"/>
</g>
<circle r="8" fill="#7f8592"/>
<circle r="3.5" fill="#4b4f5a"/>
</g>
<!-- 远侧腿(在车架后方) -->
<g id="farLeg">
<line id="farCrank" x1="455" y1="454" x2="455" y2="418"
stroke="#4c515c" stroke-width="7" stroke-linecap="round"/>
<path id="farThigh" d="" fill="none" stroke="#c9782f" stroke-width="19"
stroke-linecap="round" stroke-linejoin="round"/>
<path id="farShin" d="" fill="none" stroke="#c9782f" stroke-width="11"
stroke-linecap="round" stroke-linejoin="round"/>
<g id="farPedal">
<rect x="-14" y="-4" width="28" height="8" rx="3" fill="#2f333c"/>
<path d="M-12 -9 Q0 -15 12 -11 L26 -4 Q28 0 22 2 L-10 2 Q-15 2 -15 -3 Z" fill="#c9782f"/>
</g>
</g>
<!-- 链条 -->
<path id="chain"
d="M455 428 L340 442 A10 10 0 0 0 340 462 L455 480 A26 26 0 0 0 455 428 Z"
fill="none" stroke="#7d838f" stroke-width="4" stroke-dasharray="6 5"/>
<!-- 车架 -->
<g fill="none" stroke="#2e6b7a" stroke-width="9" stroke-linecap="round">
<path d="M455 454 L340 452"/>
<path d="M402 322 L340 452"/>
<path d="M455 454 L402 322"/>
<path d="M455 454 L588 366"/>
<path d="M402 322 L578 328"/>
<path d="M578 328 L588 366"/>
<path d="M588 366 L600 452"/>
</g>
<!-- 牙盘 -->
<circle cx="455" cy="454" r="26" fill="none" stroke="#8b909c" stroke-width="5"
stroke-dasharray="3 5"/>
<circle cx="455" cy="454" r="17" fill="#5b606b"/>
<circle cx="455" cy="454" r="5" fill="#3a3e48"/>
<!-- 车座 -->
<path d="M352 316 C366 306 390 304 404 308 L444 318 C434 326 392 330 360 326 Z"
fill="#4a3f36"/>
<!-- 车把 -->
<path d="M578 328 L578 306 Q578 292 596 290 L634 290"
fill="none" stroke="#3a3a44" stroke-width="8" stroke-linecap="round"/>
<circle cx="634" cy="290" r="7" fill="#4a3f36"/>
<!-- ================= 鹈鹕 ================= -->
<!-- 近侧腿(独立于身体,脚踩踏板) -->
<g id="nearLeg">
<line id="nearCrank" x1="455" y1="454" x2="455" y2="490"
stroke="#5b606b" stroke-width="7" stroke-linecap="round"/>
<path id="nearThigh" d="" fill="none" stroke="#e08a3c" stroke-width="20"
stroke-linecap="round" stroke-linejoin="round"/>
<path id="nearShin" d="" fill="none" stroke="#e08a3c" stroke-width="11"
stroke-linecap="round" stroke-linejoin="round"/>
<g id="nearPedal">
<rect x="-14" y="-4" width="28" height="8" rx="3" fill="#3a3e48"/>
<path d="M-12 -9 Q0 -15 12 -11 L26 -4 Q28 0 22 2 L-10 2 Q-15 2 -15 -3 Z" fill="#e08a3c"/>
</g>
</g>
<!-- 身体/头/翅膀:随踩踏起伏 -->
<g id="pelicanBob">
<g id="pelican">
<!-- 尾羽 -->
<path d="M350 268 C320 262 296 248 282 228 C306 236 334 246 352 252 Z" fill="#e7dfd0"/>
<path d="M344 276 C316 276 294 268 276 252 C304 256 330 262 348 266 Z"
fill="#efe8da" opacity="0.9"/>
<!-- 身体 -->
<path d="M404 210
C444 210 468 238 466 276
C464 314 438 336 404 336
C368 336 340 314 338 276
C336 238 362 210 404 210 Z"
fill="url(#bodyGrad)"/>
<!-- 脖子 -->
<path d="M434 256 C442 220 458 192 490 178 L524 200 C498 214 482 238 472 272 Z"
fill="url(#bodyGrad)"/>
<!-- 头 -->
<ellipse cx="516" cy="174" rx="35" ry="30" fill="#fffdf8"
transform="rotate(-10 516 174)"/>
<!-- 头顶小羽毛 -->
<path d="M498 148 C500 132 512 122 524 124 C514 132 508 140 506 150 Z" fill="#f2ebdd"/>
<!-- 喉囊 -->
<path d="M534 178 C588 182 636 188 672 196
C658 230 612 254 574 244
C544 236 528 206 534 178 Z"
fill="#f8c78b"/>
<path d="M556 196 C586 202 616 210 646 216 C632 232 606 242 582 236
C562 230 552 212 556 196 Z"
fill="#fbd9a8" opacity="0.75"/>
<!-- 上喙 -->
<path d="M530 156 C582 158 636 172 674 190 L670 198 C634 182 584 176 532 176 Z"
fill="#efa33c"/>
<!-- 喙尖钩 -->
<path d="M668 192 C676 194 680 200 678 208 C674 202 668 198 662 196 Z" fill="#dd8f2b"/>
<!-- 鼻孔 -->
<ellipse cx="566" cy="168" rx="6" ry="3" fill="#d9822a" opacity="0.7"/>
<!-- 眼睛 -->
<circle cx="514" cy="166" r="8.5" fill="#2b2b33"/>
<circle cx="517" cy="163" r="3" fill="#ffffff" opacity="0.95"/>
<ellipse id="lid" cx="514" cy="166" rx="11" ry="0" fill="#fffdf8"/>
</g>
<!-- 翅膀(握把处固定,肩部随身体起伏) -->
<g id="wingGroup">
<path id="wing" d="" fill="url(#wingGrad)"/>
<path id="wingFeathers" d="" fill="none" stroke="#d9cfbc" stroke-width="1.8"
stroke-linecap="round" opacity="0.75"/>
<g transform="translate(634 290)">
<path d="M-8 -11 C6 -13 15 -4 12 4 C7 -4 -1 -6 -8 -4 Z" fill="#f7f2e7"/>
<path d="M-8 -2 C3 -5 12 2 10 9 C5 3 -2 1 -8 3 Z" fill="#efe8d9"/>
</g>
</g>
</g><!-- /pelicanBob -->
</svg>
<script>
(function () {
const NS = 'http://www.w3.org/2000/svg';
const $ = id => document.getElementById(id);
/ ---------- 背景程序化生成 ---------- /
// 周期为 900 的正弦叠加,保证左右无缝衔接
function hillD(base, amp) {
let d = '';
for (let x = 0; x <= 900; x += 6) {
const t = (x / 900) Math.PI 2;
const y = base - amp Math.sin(t 2) - amp 0.42 Math.sin(t * 5 + 1.1);
d += (x === 0 ? 'M' : 'L') + x + ' ' + y.toFixed(1);
}
return d + 'L900 528L0 528Z';
}
$('hillFarPath').setAttribute('d', hillD(398, 42));
$('hillNearPath').setAttribute('d', hillD(424, 30));
// 灌木带(-300 起铺到 1200,覆盖宽屏裁切区)
const bushBand = $('bushBand');
for (let i = 0; i < 36; i++) {
const u = document.createElementNS(NS, 'use');
u.setAttribute('href', '#bush');
const x = -300 + i 80 + (i % 3) 19;
const y = 500 + (i % 4) * 5;
const s = 0.66 + (i % 5) * 0.12;
u.setAttribute('transform', translate(${x} ${y}) scale(${s}));
u.setAttribute('fill', i % 2 ? '#4f8f6b' : '#5b9d78');
bushBand.appendChild(u);
}
// 路面虚线
const dashBand = $('dashBand');
for (let i = 0; i < 14; i++) {
const u = document.createElementNS(NS, 'use');
u.setAttribute('href', '#dash');
u.setAttribute('x', -300 + i * 150);
u.setAttribute('y', 578);
dashBand.appendChild(u);
}
/ ---------- 滚动视差 ---------- /
const scroll = [
{ el: $('hillsFar'), x: 0, v: 10 },
{ el: $('hillsNear'), x: 0, v: 19 },
{ el: bushBand, x: 0, v: 46 },
{ el: dashBand, x: 0, v: 250 }
];
const clouds = [...document.querySelectorAll('.cloud')].map(el => ({
el,
x: +el.dataset.x,
y: +el.dataset.y,
v: +el.dataset.v,
s: +el.dataset.s
}));
/ ---------- 骑行几何 ---------- /
const BB = { x: 455, y: 454 }; // 中轴
const CRANK = 36; // 曲柄长度
const HIP = { x: 418, y: 330 }; // 髋关节(坐垫上方)
const HIP_F = { x: 412, y: 326 }; // 远侧髋
const L1 = 92, L2 = 84; // 大腿 / 小腿
// 两段式 IK:膝盖始终向前(+x)弯曲
function knee(hp, fp) {
const dx = fp.x - hp.x, dy = fp.y - hp.y;
const d = Math.max(1, Math.hypot(dx, dy));
const ux = dx / d, uy = dy / d;
// 目标超出腿长时做等比缩放,避免 NaN
const dc = Math.min(d, L1 + L2 - 0.5);
const a = (L1 L1 - L2 L2 + dc dc) / (2 dc);
const h = Math.sqrt(Math.max(0, L1 L1 - a a));
return {
x: hp.x + ux a + uy h,
y: hp.y + uy a - ux h
};
}
function setLeg(prefix, hip, foot, hipY) {
const h = { x: hip.x, y: hip.y + hipY };
const k = knee(h, foot);
$(prefix + 'Crank').setAttribute('x2', foot.x.toFixed(2));
$(prefix + 'Crank').setAttribute('y2', foot.y.toFixed(2));
$(prefix + 'Thigh').setAttribute('d',M${h.x} ${h.y.toFixed(2)} L${k.x.toFixed(2)} ${k.y.toFixed(2)});
$(prefix + 'Shin').setAttribute('d',M${k.x.toFixed(2)} ${k.y.toFixed(2)} L${foot.x.toFixed(2)} ${foot.y.toFixed(2)});
$(prefix + 'Pedal').setAttribute('transform',translate(${foot.x.toFixed(2)} ${foot.y.toFixed(2)}));
}
/ ---------- 状态 ---------- /
let last = performance.now();
let crankA = 0;
let wheelA = 0;
let chainOff = 0;
const blink = { t: 0, next: 1.6, on: false };
const lid = $('lid');
const wingEl = $('wing');
function updateWing(bob) {
const sy = 256 + bob;
const gx = 634, gy = 290;
wingEl.setAttribute('d',
`M432 ${sy.toFixed(2)}
C520 ${(sy - 2).toFixed(2)} 592 ${(272 + bob * 0.4).toFixed(2)} ${gx} ${gy}
C590 ${(306 - bob * 0.3).toFixed(2)} 518 ${(sy + 42).toFixed(2)} 432 ${(sy + 32).toFixed(2)} Z`);
// 三根飞羽线,从肩部向握把方向渐收
const lines = [];
for (let i = 0; i < 3; i++) {
const t = 0.26 + i * 0.17;
const x0 = 452 + i * 26;
const y0 = sy + 12 + i * 7;
const x1 = 452 + (gx - 452) (0.55 + t 0.42);
const y1 = gy - 4 + i * 3;
lines.push(M${x0} ${y0.toFixed(2)} Q${(x0 + x1) / 2} ${(y0 + y1) / 2 - 4} ${x1.toFixed(2)} ${y1});
}
$('wingFeathers').setAttribute('d', lines.join(' '));
}
/ ---------- 主循环 ---------- /
function tick(now) {
const dt = Math.min(0.05, (now - last) / 1000);
last = now;
// 视差滚动
for (const s of scroll) {
s.x -= s.v * dt;
if (s.x <= -900) s.x += 900;
s.el.setAttribute('transform', translate(${s.x.toFixed(2)} 0));
}
// 云
for (const c of clouds) {
c.x -= c.v * dt;
if (c.x < -260) c.x += 1500;
c.el.setAttribute('transform',translate(${c.x.toFixed(2)} ${c.y}) scale(${c.s}));
}
// 曲柄(1.45 圈/秒)
const cadence = 1.45;
crankA += cadence Math.PI 2 * dt;
// 车轮(齿比 2.6)
wheelA = (wheelA + cadence 360 2.6 * dt) % 360;
$('rearSpokes').setAttribute('transform', rotate(${wheelA.toFixed(2)}));
$('frontSpokes').setAttribute('transform', rotate(${wheelA.toFixed(2)}));
// 链条流动
chainOff -= dt * 42;
$('chain').setAttribute('stroke-dashoffset', chainOff.toFixed(1));
// 脚踏位置(SVG 坐标 y 向下,crankA 增大 = 顺时针)
const cos = Math.cos(crankA), sin = Math.sin(crankA);
const footNear = { x: BB.x + CRANK cos, y: BB.y + CRANK sin };
const footFar = { x: BB.x - CRANK cos, y: BB.y - CRANK sin };
// 身体起伏(每半圈一次)——髋部随之上下,腿保持踩实踏板
const bob = Math.sin(crankA 2) 2.2;
$('pelicanBob').setAttribute('transform', translate(0 ${bob.toFixed(2)}));
setLeg('near', HIP, footNear, bob);
setLeg('far', HIP_F, footFar, bob);
updateWing(bob);
// 眨眼
blink.t += dt;
if (!blink.on && blink.t > blink.next) {
blink.on = true;
blink.t = 0;
} else if (blink.on) {
const p = Math.min(1, blink.t / 0.15);
const ry = (p < 0.5 ? p 2 : (1 - p) 2) * 10;
lid.setAttribute('ry', ry.toFixed(1));
if (p >= 1) {
blink.on = false;
blink.t = 0;
blink.next = 1.8 + Math.random() * 3.6;
lid.setAttribute('ry', 0);
}
}
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
})();
</script>
</body>
</html>
最后生成


(网站上可能有点卡实际比较流畅)