Gemini3.8 flash鹈鹕骑单车 我觉得产出效果还可以

nodeseeek 2026-09-03 00:08 1

我觉得效果还可以,虽然是让3.1Pro优化了下prompt,但是成品的一次过的


<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>鹈鹕骑自行车 - 2D 循环动画</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
width: 100vw;
height: 100vh;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
background: radial-gradient(circle at 50% 30%, #bbf2f6 0%, #86d3e3 50%, #5cb8cf 100%);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

.canvas-container {
width: 95vw;
max-width: 1000px;
height: 85vh;
max-height: 680px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}

svg {
width: 100%;
height: 100%;
overflow: hidden;
border-radius: 28px;
box-shadow: 0 25px 60px rgba(18, 52, 77, 0.25), 0 8px 20px rgba(0, 0, 0, 0.08);
background: linear-gradient(to bottom, #d4f4fb 0%, #eefbfd 62%, #a8d5ba 62.1%, #7cb896 66%, #525a66 66.1%, #353b45 100%);
}

/* ================= CSS 循环动画体系 ================= */

/* 1. 车轮 360° 匀速顺时针旋转 (周期与路面位移速度严格匹配) */
.wheel-spokes {
animation: spin 1.1s linear infinite;
transform-box: fill-box;
transform-origin: center;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}

/* 2. 背景与环境无限无缝平移 (向左滚动制造向前冲刺感) */
.scroll-clouds {
animation: scrollH 22s linear infinite;
}
.scroll-hills {
animation: scrollH 10s linear infinite;
}
.scroll-trees {
animation: scrollH 4.4s linear infinite;
}
.scroll-road-dashes {
animation: scrollRoad 1.1s linear infinite;
}
.scroll-bushes {
animation: scrollH 2.2s linear infinite;
}

@keyframes scrollH {
from { transform: translateX(0); }
to { transform: translateX(-900px); }
}

@keyframes scrollRoad {
from { transform: translateX(0); }
to { transform: translateX(-440px); }
}

/* 3. 鹈鹕躯干呼吸式律动 (上下起伏 + 微倾角度) */
.pelican-rider {
animation: pelicanBob 1.1s cubic-bezier(0.45, 0.05, 0.55, 0.95) infinite;
transform-origin: 390px 320px;
}
@keyframes pelicanBob {
0%, 100% { transform: translateY(0px) rotate(0deg); }
25% { transform: translateY(-5px) rotate(-0.8deg); }
50% { transform: translateY(2px) rotate(0.4deg); }
75% { transform: translateY(-4px) rotate(-0.5deg); }
}

/* 4. 标志性大鸟囊弹性微颤 (体现充沛弹性与趣味) */
.gular-pouch {
animation: pouchJiggle 1.1s ease-in-out infinite;
transform-origin: 520px 170px;
}
@keyframes pouchJiggle {
0%, 100% { transform: scale(1) rotate(0deg); }
35% { transform: scale(1.02, 0.96) rotate(1deg); }
70% { transform: scale(0.98, 1.03) rotate(-1deg); }
}

/* 5. 随风飞扬的红色围巾飘荡 */
.scarf-tail-1 {
animation: scarfFly1 0.55s ease-in-out infinite alternate;
transform-origin: 405px 215px;
}
.scarf-tail-2 {
animation: scarfFly2 0.7s ease-in-out infinite alternate;
transform-origin: 405px 215px;
}
@keyframes scarfFly1 {
0% { transform: rotate(-4deg) skewX(2deg); }
100% { transform: rotate(10deg) skewX(-7deg) scaleY(0.92); }
}
@keyframes scarfFly2 {
0% { transform: rotate(8deg) skewY(-3deg); }
100% { transform: rotate(-8deg) skewY(6deg) scaleY(1.08); }
}

/* 6. 自行车整体微弱的路面颠簸震颤 */
.bike-chassis {
animation: bikeJitter 0.55s ease-in-out infinite alternate;
transform-origin: 450px 460px;
}
@keyframes bikeJitter {
0% { transform: translateY(0); }
100% { transform: translateY(1.2px); }
}
</style>
</head>
<body>

<div class="canvas-container">
<svg id="scene" viewBox="0 0 900 600" preserveAspectRatio="xMidYMid slice" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- 基础色彩渐变定义 -->
<linearGradient id="sunGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fff6cc" />
<stop offset="100%" stop-color="#ffdd6b" />
</linearGradient>

<linearGradient id="pouchGrad" x1="0%" y1="0%" x2="60%" y2="100%">
<stop offset="0%" stop-color="#ffa42b" />
<stop offset="70%" stop-color="#f57c00" />
<stop offset="100%" stop-color="#e65100" />
</linearGradient>

<linearGradient id="frameGrad" x1="0%" y1="0%" x2="100%" y2="50%">
<stop offset="0%" stop-color="#2bd9b6" />
<stop offset="100%" stop-color="#14a085" />
</linearGradient>

<linearGradient id="tireGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3d444f" />
<stop offset="100%" stop-color="#22272e" />
</linearGradient>

<!-- 车轮辐条复用单元 -->
<g id="spoke-cluster">
<line x1="0" y1="-56" x2="0" y2="56" stroke="#c0d3d8" stroke-width="2" />
<line x1="-56" y1="0" x2="56" y2="0" stroke="#c0d3d8" stroke-width="2" />
<line x1="-40" y1="-40" x2="40" y2="40" stroke="#c0d3d8" stroke-width="1.8" />
<line x1="-40" y1="40" x2="40" y2="-40" stroke="#c0d3d8" stroke-width="1.8" />
<line x1="-52" y1="-21" x2="52" y2="21" stroke="#a0b5bb" stroke-width="1.5" />
<line x1="-21" y1="-52" x2="21" y2="52" stroke="#a0b5bb" stroke-width="1.5" />
<line x1="-52" y1="21" x2="52" y2="-21" stroke="#a0b5bb" stroke-width="1.5" />
<line x1="-21" y1="52" x2="21" y2="-52" stroke="#a0b5bb" stroke-width="1.5" />
</g>
</defs>

<!-- ================= 背景层:太阳与无缝远景 ================= -->
<g id="background-sky">
<!-- 温暖的晨阳与光环 -->
<circle cx="750" cy="120" r="85" fill="#fff9db" opacity="0.4" />
<circle cx="750" cy="120" r="55" fill="url(#sunGrad)" />

<!-- 飘动的扁平多边形白云 (两组拼合实现无缝平移) -->
<g class="scroll-clouds">
<g>
<path d="M 120 110 q 25 -30 60 -10 q 30 -25 60 5 q 25 -10 45 15 l -170 0 z" fill="#ffffff" opacity="0.82" />
<path d="M 460 70 q 35 -35 75 -5 q 30 -25 65 0 q 30 -10 50 15 l -195 0 z" fill="#ffffff" opacity="0.65" />
<path d="M 720 130 q 20 -20 45 -5 q 25 -20 50 5 l -100 0 z" fill="#ffffff" opacity="0.75" />
</g>
<g transform="translate(900, 0)">
<path d="M 120 110 q 25 -30 60 -10 q 30 -25 60 5 q 25 -10 45 15 l -170 0 z" fill="#ffffff" opacity="0.82" />
<path d="M 460 70 q 35 -35 75 -5 q 30 -25 65 0 q 30 -10 50 15 l -195 0 z" fill="#ffffff" opacity="0.65" />
<path d="M 720 130 q 20 -20 45 -5 q 25 -20 50 5 l -100 0 z" fill="#ffffff" opacity="0.75" />
</g>
</g>

<!-- 远山脉叠层 (向左平移) -->
<g class="scroll-hills">
<g fill="#9acdb5">
<polygon points="0,375 80,310 180,375 290,290 410,375 520,325 650,375 760,295 880,375 900,375 900,375 0,375" />
</g>
<g transform="translate(900, 0)" fill="#9acdb5">
<polygon points="0,375 80,310 180,375 290,290 410,375 520,325 650,375 760,295 880,375 900,375 900,375 0,375" />
</g>
</g>

<!-- 扁平化绿树与矮灌木层 -->
<g class="scroll-trees">
<g>
<!-- 几何圆树 -->
<rect x="70" y="345" width="8" height="30" fill="#69513d" />
<circle cx="74" cy="330" r="24" fill="#4ea672" />
<rect x="340" y="340" width="10" height="35" fill="#69513d" />
<polygon points="315,350 345,280 375,350" fill="#368f5b" />
<rect x="620" y="348" width="7" height="28" fill="#69513d" />
<circle cx="623" cy="336" r="20" fill="#60b884" />
<circle cx="633" cy="340" r="14" fill="#4ea672" />
</g>
<g transform="translate(900, 0)">
<rect x="70" y="345" width="8" height="30" fill="#69513d" />
<circle cx="74" cy="330" r="24" fill="#4ea672" />
<rect x="340" y="340" width="10" height="35" fill="#69513d" />
<polygon points="315,350 345,280 375,350" fill="#368f5b" />
<rect x="620" y="348" width="7" height="28" fill="#69513d" />
<circle cx="623" cy="336" r="20" fill="#60b884" />
<circle cx="633" cy="340" r="14" fill="#4ea672" />
</g>
</g>
</g>

<!-- ================= 地面与道路 ================= -->
<g id="ground-and-road">
<!-- 沥青路面 -->
<rect x="0" y="396" width="900" height="204" fill="#3a404a" />
<!-- 路肩石分界线 -->
<rect x="0" y="396" width="900" height="7" fill="#f1c40f" />

<!-- 疾驰掠过的路面虚线 -->
<g class="scroll-road-dashes" stroke="#ffffff" stroke-width="7" stroke-linecap="round" opacity="0.85">
<line x1="20" y1="520" x2="110" y2="520" />
<line x1="160" y1="520" x2="250" y2="520" />
<line x1="300" y1="520" x2="390" y2="520" />
<line x1="440" y1="520" x2="530" y2="520" />
<line x1="580" y1="520" x2="670" y2="520" />
<line x1="720" y1="520" x2="810" y2="520" />
<line x1="860" y1="520" x2="950" y2="520" />
<line x1="1000" y1="520" x2="1090" y2="520" />
<line x1="1140" y1="520" x2="1230" y2="520" />
<line x1="1280" y1="520" x2="1370" y2="520" />
</g>
</g>

<!-- ================= 动态主体:自行车与鹈鹕骑士 ================= -->
<g id="bicycle-and-pelican">
<!-- 地面接触阴影 (随骑行产生弹性形变) -->
<ellipse id="shadow" cx="440" cy="512" rx="265" ry="14" fill="#1b2129" opacity="0.45" />

<!-- ================= 1. 远端腿与踏板 (背景层,位于车身之后) ================= -->
<g id="far-leg-group">
<!-- 远端曲柄 -->
<line id="crank-far" x1="435" y1="445" x2="410" y2="465" stroke="#718096" stroke-width="7" stroke-linecap="round" />
<!-- 远端脚踏板 -->
<rect id="pedal-far" x="396" y="462" width="26" height="7" rx="3" fill="#2d3748" />
<!-- 远端大腿与小腿 (深橙色阴影腿) -->
<path id="leg-far" d="M 385 300 Q 380 370 410 465" fill="none" stroke="#d96b00" stroke-width="14" stroke-linecap="round" stroke-linejoin="round" />
<!-- 远端蹼足 -->
<path id="foot-far" d="M 400 465 L 428 465 L 415 455 Z" fill="#b85300" />
</g>

<!-- ================= 2. 经典复古自行车实体 ================= -->
<g id="bicycle-frame" class="bike-chassis">
<!-- 后轮组 (圆心: 255, 442) -->
<g id="rear-wheel" transform="translate(255, 442)">
<!-- 轮胎 -->
<circle cx="0" cy="0" r="68" fill="none" stroke="url(#tireGrad)" stroke-width="12" />
<circle cx="0" cy="0" r="62" fill="none" stroke="#e6edf0" stroke-width="3" />
<!-- 辐条组 (CSS旋转) -->
<g class="wheel-spokes">
<use href="#spoke-cluster" />
</g>
<!-- 轴心 -->
<circle cx="0" cy="0" r="11" fill="#4a5568" />
<circle cx="0" cy="0" r="5" fill="#f7fafc" />
<!-- 后挡泥板 -->
<path d="M -66 0 A 66 66 0 0 1 45 -48" fill="none" stroke="#2bd9b6" stroke-width="9" stroke-linecap="round" />
</g>

<!-- 前轮组 (圆心: 635, 442) -->
<g id="front-wheel" transform="translate(635, 442)">
<!-- 轮胎 -->
<circle cx="0" cy="0" r="68" fill="none" stroke="url(#tireGrad)" stroke-width="12" />
<circle cx="0" cy="0" r="62" fill="none" stroke="#e6edf0" stroke-width="3" />
<!-- 辐条组 (CSS旋转) -->
<g class="wheel-spokes">
<use href="#spoke-cluster" />
</g>
<!-- 轴心 -->
<circle cx="0" cy="0" r="11" fill="#4a5568" />
<circle cx="0" cy="0" r="5" fill="#f7fafc" />
<!-- 前挡泥板 -->
<path d="M -40 -52 A 66 66 0 0 1 65 -10" fill="none" stroke="#2bd9b6" stroke-width="9" stroke-linecap="round" />
</g>

<!-- 复古流线型车架管件结构 -->
<g id="frame-tubes" stroke="url(#frameGrad)" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" fill="none">
<!-- 平衡下叉 (后轴到中轴) -->
<line x1="255" y1="442" x2="435" y2="445" />
<!-- 后上叉 (后轴到座管下接头) -->
<line x1="255" y1="442" x2="375" y2="330" />
<!-- 立管 (座管到底部中轴) -->
<line x1="375" y1="330" x2="435" y2="445" />
<!-- 下管 (车头腕到底部中轴) -->
<line x1="575" y1="315" x2="435" y2="445" />
<!-- 弧形复古主上梁管 -->
<path d="M 375 340 C 430 330, 520 310, 575 315" />
<!-- 前叉 (前轮轴至把手立管) -->
<line x1="635" y1="442" x2="575" y2="315" stroke="#22aa8e" />
</g>

<!-- 镀铬车把立管与优雅向后弯折燕把 -->
<path d="M 575 315 L 565 242 C 555 238, 525 240, 505 255" fill="none" stroke="#cbd5e0" stroke-width="7" stroke-linecap="round" />
<!-- 橡胶握把套 -->
<path d="M 515 250 L 498 259" stroke="#744210" stroke-width="9" stroke-linecap="round" />

<!-- 前照复古大灯与铃铛 -->
<path d="M 578 285 L 595 288 L 595 300 L 578 297 Z" fill="#ffd166" />
<circle cx="578" cy="291" r="9" fill="#f6ad55" />
<circle cx="560" cy="240" r="7" fill="#ecc94b" />

<!-- 皮革坐垫与支撑减震弹簧 -->
<g id="saddle" transform="translate(370, 312)">
<line x1="5" y1="18" x2="5" y2="0" stroke="#718096" stroke-width="8" stroke-linecap="round" />
<path d="M -6 6 Q 5 12 16 6" fill="none" stroke="#a0aec0" stroke-width="3" />
<path d="M -22 0 C -15 -8, 20 -8, 32 3 C 25 7, 5 5, -8 5 C -16 5, -20 3, -22 0 Z" fill="#5c2e0b" />
</g>

<!-- 大齿盘链轮盘与金色链条 -->
<circle cx="435" cy="445" r="22" fill="#a0aec0" stroke="#718096" stroke-width="3" />
<circle cx="435" cy="445" r="8" fill="#4a5568" />
<!-- 链条外轮廓 -->
<path d="M 255 435 L 435 425 A 20 20 0 0 1 450 455 L 255 450 Z" fill="none" stroke="#d69e2e" stroke-width="3.5" stroke-dasharray="7,3" />
</g>

<!-- ================= 3. 主角:佩戴飞行护目镜的鹈鹕 ================= -->
<g id="pelican" class="pelican-rider">
<!-- 短萌俏皮小尾羽 -->
<path d="M 330 280 C 315 272, 305 285, 290 270 C 308 290, 322 295, 335 292 Z" fill="#e2e8f0" />

<!-- 丰满白皙的主躯干 (微向前俯身冲刺姿态) -->
<path d="M 345 285 C 335 235, 370 195, 415 190 C 450 186, 465 210, 455 260 C 445 305, 375 325, 345 285 Z" fill="#f8fafc" stroke="#edf2f7" stroke-width="1.5" />

<!-- 优雅且富有力量感的S形长颈 -->
<path d="M 425 205 C 435 175, 435 155, 460 145 C 475 160, 460 195, 440 215 Z" fill="#ffffff" />

<!-- 头部基底 -->
<circle cx="468" cy="142" r="23" fill="#ffffff" />

<!-- ===== 鹈鹕的灵魂:超大橙黄色喉囊 (Gular Pouch) ===== -->
<g class="gular-pouch">
<!-- 标志性弹性喉囊大口袋 -->
<path d="M 480 148 C 485 195, 520 240, 565 195 C 595 165, 630 155, 640 148 C 580 170, 515 170, 480 148 Z" fill="url(#pouchGrad)" opacity="0.95" />
<!-- 喉囊微凸的半透明高光线条 -->
<path d="M 505 168 Q 535 208 565 188" fill="none" stroke="#ffb74d" stroke-width="3" stroke-linecap="round" opacity="0.8" />
</g>

<!-- 坚硬狭长的粉黄上喙 (与尖端小勾爪) -->
<path d="M 472 135 L 638 144 C 646 145, 645 152, 636 153 L 478 152 Z" fill="#ffa726" stroke="#f57c00" stroke-width="1.5" />
<!-- 喙尖小倒钩钩爪 -->
<path d="M 636 144 Q 643 148 637 154" fill="none" stroke="#d84315" stroke-width="2.5" stroke-linecap="round" />

<!-- 炯炯有神的卡通大眼睛 -->
<ellipse cx="463" cy="133" rx="6.5" ry="7.5" fill="#2d3748" />
<circle cx="461" cy="131" r="2.5" fill="#ffffff" />
<!-- 翘起的专注自信眉毛 -->
<path d="M 454 125 Q 465 121 474 126" fill="none" stroke="#cbd5e0" stroke-width="3" stroke-linecap="round" />

<!-- 复古复古飞行员皮帽 -->
<path d="M 445 136 C 445 118, 465 116, 485 125 C 488 135, 482 142, 482 142 C 468 130, 452 132, 445 136 Z" fill="#6b4423" />
<!-- 绑带 -->
<path d="M 452 135 Q 456 152 462 154" fill="none" stroke="#4a2e16" stroke-width="3" />

<!-- 额头上酷帅的飞行员铜框护目镜 -->
<g id="goggles" transform="translate(460, 116) rotate(12)">
<rect x="-14" y="-7" width="28" height="14" rx="6" fill="#8c5828" stroke="#3d2108" stroke-width="1.5" />
<!-- 双目镜片高亮反光 -->
<circle cx="-6" cy="0" r="5.5" fill="#64d8cb" stroke="#ffe082" stroke-width="1.5" />
<circle cx="6" cy="0" r="5.5" fill="#64d8cb" stroke="#ffe082" stroke-width="1.5" />
<!-- 镜片白色斜切反光 -->
<line x1="-8" y1="-3" x2="-4" y2="3" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" />
<line x1="4" y1="-3" x2="8" y2="3" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" />
</g>

<!-- 随风迎面狂舞的红色波点围巾 (双尾随风抖动) -->
<g id="scarf-group">
<!-- 围巾尾巴 1 (飘在下方) -->
<path class="scarf-tail-1" d="M 412 218 C 365 210, 335 240, 275 220 C 325 245, 360 230, 412 226 Z" fill="#e53e3e" />
<!-- 围巾尾巴 2 (飘在上方) -->
<path class="scarf-tail-2" d="M 415 212 C 375 195, 340 215, 290 190 C 335 220, 375 210, 415 220 Z" fill="#c53030" />
<!-- 围在脖颈的主围巾圈与结 -->
<path d="M 418 202 C 438 202, 442 220, 432 226 C 418 232, 408 218, 418 202 Z" fill="#e53e3e" stroke="#9b2c2c" stroke-width="1" />
<circle cx="414" cy="220" r="4.5" fill="#feb2b2" />
</g>

<!-- 鹈鹕翅膀 (如手臂般坚定自然握住把手) -->
<!-- 翅膀主体上臂 -->
<path d="M 375 240 C 385 215, 420 220, 450 240 C 475 255, 495 256, 508 255 C 495 268, 455 285, 410 282 C 385 280, 365 260, 375 240 Z" fill="#edf2f7" stroke="#cbd5e0" stroke-width="1.5" />
<!-- 灰色层次飞羽羽翼细节 -->
<path d="M 425 265 C 455 268, 485 262, 506 254 C 490 275, 450 282, 425 280 Z" fill="#718096" />
<!-- 握住车把的拟人翅尖羽毛小手 -->
<path d="M 502 248 C 512 245, 520 252, 516 260 C 510 266, 498 262, 502 248 Z" fill="#e2e8f0" />
</g>

<!-- ================= 4. 近端腿与脚踏联动 (前景层,遮挡车架) ================= -->
<g id="near-leg-group">
<!-- 靠近观察者的链轮曲柄臂 -->
<line id="crank-near" x1="435" y1="445" x2="460" y2="425" stroke="#a0aec0" stroke-width="8" stroke-linecap="round" />
<!-- 中轴螺栓亮盖 -->
<circle cx="435" cy="445" r="7" fill="#edf2f7" />
<!-- 近端脚踏板 -->
<rect id="pedal-near" x="445" y="420" width="28" height="8" rx="3.5" fill="#1a202c" stroke="#4a5568" stroke-width="1.5" />

<!-- 具有 IK 动态的近端强健大腿与小腿 -->
<path id="thigh-near" d="M 390 295 L 430 365" fill="none" stroke="#f6ad55" stroke-width="16" stroke-linecap="round" />
<path id="shin-near" d="M 430 365 L 458 424" fill="none" stroke="#ed8936" stroke-width="13" stroke-linecap="round" />

<!-- 亮橙色鲜明鸟蹼足 (稳稳踏在踏板上) -->
<g id="foot-near-group">
<path id="foot-near" d="M 445 422 L 478 422 L 465 410 Z" fill="#dd6b20" />
</g>
</g>
</g>

<!-- 前景近景:极速掠过的草叶质感层 (增加空间进深) -->
<g class="scroll-bushes" fill="#2d3748" opacity="0.15">
<polygon points="120,590 140,550 160,590" />
<polygon points="450,595 470,560 490,595" />
<polygon points="760,590 785,545 810,590" />
</g>
</svg>
</div>

<!-- ================= 精密腿部逆运动学 (IK) 动力联动脚本 ================= -->
<script>
(function () {
// 核心几何锚点参数 (基于 SVG ViewBox 坐标系统 900x600)
const CRANK_CENTER = { x: 435, y: 445 }; // 中轴中心
const CRANK_RADIUS = 30; // 踏板回转半径

// 鹈鹕髋关节基础挂载点 (坐垫上方臀部)
const HIP_BASE = { x: 388, y: 298 };

// 鸟类腿骨长度 (大腿与小腿骨骼比例)
const THIGH_LEN = 78;
const SHIN_LEN = 76;

// 获取各交互 SVG DOM 节点引用
const crankNear = document.getElementById('crank-near');
const pedalNear = document.getElementById('pedal-near');
const thighNear = document.getElementById('thigh-near');
const shinNear = document.getElementById('shin-near');
const footNear = document.getElementById('foot-near');

const crankFar = document.getElementById('crank-far');
const pedalFar = document.getElementById('pedal-far');
const legFar = document.getElementById('leg-far');
const footFar = document.getElementById('foot-far');

const shadow = document.getElementById('shadow');

// 骑行时间步进变量
let angle = 0;
// 速度参数:与车轮 CSS 旋转周期 1.1s 保持高精度数学同步 (2 * PI / (1.1s * 60fps) ≈ 0.095 rad/frame)
const speed = 0.0952;

// 2-Bone 逆向运动学求解器 (IK Solver)
// 计算给定臀部(h)与脚踏板(f)位置时,向前弯曲的膝关节(K)坐标
function solveKnee(h, f, l1, l2) {
const dx = f.x - h.x;
const dy = f.y - h.y;
const dist = Math.sqrt(dx * dx + dy * dy);

// 极限拉伸保护(避免开方负数导致关节脱臼)
const clampedDist = Math.min(dist, l1 + l2 - 0.01);

// 余弦定理计算大腿与目标基准线的夹角
const baseAngle = Math.atan2(dy, dx);
const cosAngle = (l1 * l1 + clampedDist * clampedDist - l2 * l2) / (2 * l1 * clampedDist);
const flexAngle = Math.acos(Math.max(-1, Math.min(1, cosAngle)));

// 鸟类向前蹬踏膝盖向前突出弯折 (取减号使其膝盖朝右/朝前)
const kneeAngle = baseAngle - flexAngle;

return {
x: h.x + l1 * Math.cos(kneeAngle),
y: h.y + l1 * Math.sin(kneeAngle)
};
}

function animate() {
angle += speed;

// 鹈鹕由于踩踏用力引发的臀部微小生理位移 (Bobbing 联动)
const hipBobY = Math.sin(angle * 2) * 2.8;
const currentHip = {
x: HIP_BASE.x + Math.sin(angle) * 1.2,
y: HIP_BASE.y + hipBobY
};

// 地面阴影随下压节奏产生缩放与透明度呼吸感
if (shadow) {
const sScale = 265 + Math.sin(angle * 2) * 6;
shadow.setAttribute('rx', sScale);
shadow.setAttribute('opacity', 0.42 + Math.cos(angle * 2) * 0.05);
}

// ================= A. 前景近端腿动力学计算 =================
const pedalNearPos = {
x: CRANK_CENTER.x + CRANK_RADIUS * Math.cos(angle),
y: CRANK_CENTER.y + CRANK_RADIUS * Math.sin(angle)
};

// 求解近端膝盖位置
const kneeNear = solveKnee(currentHip, pedalNearPos, THIGH_LEN, SHIN_LEN);

// 渲染近端曲柄与踏板
crankNear.setAttribute('x1', CRANK_CENTER.x);
crankNear.setAttribute('y1', CRANK_CENTER.y);
crankNear.setAttribute('x2', pedalNearPos.x);
crankNear.setAttribute('y2', pedalNearPos.y);

pedalNear.setAttribute('x', pedalNearPos.x - 14);
pedalNear.setAttribute('y', pedalNearPos.y - 4);

// 渲染近端骨骼连线
thighNear.setAttribute('d', `M ${currentHip.x} ${currentHip.y} L ${kneeNear.x} ${kneeNear.y}`);
shinNear.setAttribute('d', `M ${kneeNear.x} ${kneeNear.y} L ${pedalNearPos.x} ${pedalNearPos.y}`);

// 渲染贴合踏板角度的近端蹼足
footNear.setAttribute('d', `M ${pedalNearPos.x - 12} ${pedalNearPos.y + 1} L ${pedalNearPos.x + 18} ${pedalNearPos.y + 1} L ${pedalNearPos.x + 4} ${pedalNearPos.y - 8} Z`);

// ================= B. 背景远端腿动力学计算 (相位差 180° / PI) =================
const farAngle = angle + Math.PI;
const pedalFarPos = {
x: CRANK_CENTER.x + CRANK_RADIUS * Math.cos(farAngle),
y: CRANK_CENTER.y + CRANK_RADIUS * Math.sin(farAngle)
};

// 远端臀部稍微靠内侧偏移
const farHip = { x: currentHip.x - 4, y: currentHip.y - 2 };
const kneeFar = solveKnee(farHip, pedalFarPos, THIGH_LEN, SHIN_LEN);

// 渲染远端曲柄与踏板
crankFar.setAttribute('x1', CRANK_CENTER.x);
crankFar.setAttribute('y1', CRANK_CENTER.y);
crankFar.setAttribute('x2', pedalFarPos.x);
crankFar.setAttribute('y2', pedalFarPos.y);

pedalFar.setAttribute('x', pedalFarPos.x - 13);
pedalFar.setAttribute('y', pedalFarPos.y - 3.5);

// 远端腿采用连续平滑三次贝塞尔曲线绘制,显得更具空间层次感
legFar.setAttribute('d', `M ${farHip.x} ${farHip.y} Q ${kneeFar.x} ${kneeFar.y} ${pedalFarPos.x} ${pedalFarPos.y}`);
footFar.setAttribute('d', `M ${pedalFarPos.x - 10} ${pedalFarPos.y + 1} L ${pedalFarPos.x + 16} ${pedalFarPos.y + 1} L ${pedalFarPos.x + 3} ${pedalFarPos.y - 7} Z`);

requestAnimationFrame(animate);
}

// 启动平滑 60FPS 运动学计算循环
requestAnimationFrame(animate);
})();
</script>
</body>
</html>
最新回复 (7)
  • IPO 09-03 00:09
    1

    想起帝胡云

  • hoofei 09-03 00:09
    2

    不错的

  • CIYYYT 09-03 00:10
    3

    哈基米的前端还是很好看 ^-^

  • 爱云网络科技 09-03 00:28
    4

    一个个发 ,我也试试去 ^-^

  • amashazzz 09-03 00:28
    5

    貌似不错

  • 冰镇可乐 09-03 00:44
    6

    不错

  • 涤尘 09-03 01:06
    7

    哈基咪前端依然可以 ^-^

* 帖子来源NodeSeek
返回