gemini-3.7-flash 鹈鹕 这真神了吧

紫米 2026-08-19 00:38 1




gif


https://r2.535888.xyz/2026/08/xG08pjk.gif(图片大于 4 MB)


这是我测的最好的


<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>鹈鹕骑自行车 - Pelican On A Bicycle</title>
<style>
:root {
--sky-top: #70c5ff;
--sky-bottom: #e0f2fe;
--sun-color: #fde047;
--road-color: #475569;
--road-line: #f8fafc;
--grass-color: #86efac;
--grass-dark: #22c55e;
--hill-1: #93c5fd;
--hill-2: #60a5fa;
--sea-color: #38bdf8;
}

body.sunset {
--sky-top: #f97316;
--sky-bottom: #fed7aa;
--sun-color: #fb923c;
--road-color: #334155;
--road-line: #fef08a;
--grass-color: #ca8a04;
--grass-dark: #854d0e;
--hill-1: #db2777;
--hill-2: #9d174d;
--sea-color: #ea580c;
}

body.night {
--sky-top: #0f172a;
--sky-bottom: #1e1b4b;
--sun-color: #fef08a;
--road-color: #1e293b;
--road-line: #94a3b8;
--grass-color: #15803d;
--grass-dark: #14532d;
--hill-1: #312e81;
--hill-2: #1e1b4b;
--sea-color: #1e3a8a;
}

* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
}

body {
width: 100vw;
height: 100vh;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, var(--sky-top) 0%, var(--sky-bottom) 100%);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
transition: background 1s ease;
}

#scene-container {
position: relative;
width: 100%;
max-width: 1200px;
height: 700px;
max-height: 90vh;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
border-radius: 20px;
overflow: hidden;
background: linear-gradient(180deg, var(--sky-top) 0%, var(--sky-bottom) 65%, var(--sea-color) 70%, var(--grass-dark) 78%, var(--road-color) 78%);
border: 4px solid rgba(255, 255, 255, 0.3);
}

svg {
width: 100%;
height: 100%;
display: block;
}

/* UI Controls Overlay */
.controls {
position: absolute;
top: 20px;
right: 20px;
display: flex;
gap: 10px;
z-index: 50;
}

.btn {
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(8px);
border: 1px solid rgba(255, 255, 255, 0.6);
padding: 8px 16px;
border-radius: 24px;
font-size: 14px;
font-weight: 600;
color: #1e293b;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.btn:hover {
background: rgba(255, 255, 255, 1);
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
}

.btn:active {
transform: translateY(0);
}

.title-tag {
position: absolute;
top: 20px;
left: 24px;
z-index: 50;
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(8px);
border: 1px solid rgba(255, 255, 255, 0.6);
padding: 8px 18px;
border-radius: 24px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.title-tag h1 {
font-size: 16px;
font-weight: 700;
color: #0f172a;
letter-spacing: 0.5px;
}

.title-tag p {
font-size: 11px;
color: #64748b;
margin-top: 1px;
}

/* Speed indicator */
.speed-gauge {
position: absolute;
bottom: 24px;
right: 24px;
background: rgba(15, 23, 42, 0.75);
backdrop-filter: blur(8px);
padding: 10px 18px;
border-radius: 16px;
color: #fff;
display: flex;
align-items: baseline;
gap: 6px;
z-index: 50;
border: 1px solid rgba(255, 255, 255, 0.15);
}
.speed-gauge .val {
font-size: 24px;
font-weight: 800;
color: #38bdf8;
font-family: monospace;
}
.speed-gauge .unit {
font-size: 12px;
color: #94a3b8;
}

/* Bell ripple animation on click */
.bell-sound-wave {
pointer-events: none;
animation: sound-ping 0.8s ease-out forwards;
transform-origin: center;
}

@keyframes sound-ping {
0% { r: 10px; opacity: 0.9; stroke-width: 4px; }
100% { r: 70px; opacity: 0; stroke-width: 1px; }
}

/* Scarf wave animation */
@keyframes scarf-flutter {
0%, 100% { transform: rotate(0deg) skewY(0deg); }
50% { transform: rotate(-5deg) skewY(-8deg); }
}

/* Fish wiggle */
@keyframes fish-wiggle {
0%, 100% { transform: rotate(-4deg); }
50% { transform: rotate(6deg); }
}
</style>
</head>
<body>
<div id="scene-container">
<div class="title-tag">
<h1>🚴‍♂️ 快乐的骑行鹈鹕 (Pelican Ride)</h1>
<p>按键盘 空格 或 点击加速 / 响铃</p>
</div>

<div class="controls">
<button class="btn" id="btn-bell" title="按铃铛">🔔 叮叮叮</button>
<button class="btn" id="btn-speed" title="加速/巡航">⚡ 加速</button>
<button class="btn" id="btn-theme" title="切换时段">🌅 切换天空</button>
</div>

<div class="speed-gauge">
<span class="val" id="speed-val">28</span>
<span class="unit">km/h</span>
</div>

<svg id="bike-world" viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid slice">
<defs>
<!-- Gradients -->
<linearGradient id="sun-grad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#fff" stop-opacity="0.9" />
<stop offset="100%" stop-color="var(--sun-color)" />
</linearGradient>

<linearGradient id="sea-grad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="var(--sea-color)" stop-opacity="0.8" />
<stop offset="100%" stop-color="#0284c7" />
</linearGradient>

<linearGradient id="pouch-grad" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#fdba74" />
<stop offset="60%" stop-color="#fb923c" />
<stop offset="100%" stop-color="#ea580c" />
</linearGradient>

<linearGradient id="feather-grad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#ffffff" />
<stop offset="85%" stop-color="#f1f5f9" />
<stop offset="100%" stop-color="#cbd5e1" />
</linearGradient>

<linearGradient id="frame-grad" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#06b6d4" />
<stop offset="100%" stop-color="#0e7490" />
</linearGradient>

<linearGradient id="metallic" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#f8fafc" />
<stop offset="50%" stop-color="#94a3b8" />
<stop offset="100%" stop-color="#64748b" />
</linearGradient>

<filter id="shadow" x="-10%" y="-10%" width="130%" height="130%">
<feDropShadow dx="0" dy="4" stdDeviation="3" flood-opacity="0.2" />
</filter>

<filter id="bike-ground-shadow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceGraphic" stdDeviation="6" />
</filter>
</defs>

<!-- Celestial Body (Sun/Moon) -->
<g id="celestial-group">
<circle id="sun" cx="950" cy="140" r="48" fill="url(#sun-grad)" opacity="0.9" />
<circle id="sun-glow" cx="950" cy="140" r="75" fill="var(--sun-color)" opacity="0.25" />
</g>

<!-- Parallax Layer 1: Distant Islands & Mountains -->
<g id="mountains-far"></g>

<!-- Parallax Layer 2: Sea / Lake Waves -->
<rect x="0" y="470" width="1200" height="70" fill="url(#sea-grad)" />
<g id="sea-ripples"></g>

<!-- Parallax Layer 3: Hills & Vegetation -->
<g id="hills-mid"></g>

<!-- Clouds -->
<g id="clouds-layer"></g>

<!-- Road & Ground -->
<g id="road-layer">
<!-- Grass strip -->
<rect x="0" y="520" width="1200" height="25" fill="var(--grass-dark)" />
<rect x="0" y="522" width="1200" height="12" fill="var(--grass-color)" opacity="0.6" />
<!-- Road Asphalt -->
<rect x="0" y="545" width="1200" height="155" fill="var(--road-color)" />
<rect x="0" y="545" width="1200" height="8" fill="#334155" opacity="0.5" />
<!-- Moving Road Markings -->
<g id="road-lines"></g>
<!-- Moving roadside flowers/grass posts -->
<g id="roadside-details"></g>
</g>

<!-- Speed Wind Particles -->
<g id="wind-particles"></g>

<!-- ================= MAIN CHARACTER & BIKE (Pelican on Bicycle) ================= -->
<!-- Positioned around center: X: 520, Ground Level: Y: 575 -->
<g id="pelican-cyclist" transform="translate(480, 260)">

<!-- Ground Contact Shadow -->
<ellipse id="ground-shadow" cx="120" cy="315" rx="140" ry="14" fill="#0f172a" opacity="0.4" filter="url(#bike-ground-shadow)" />

<!-- BIKE REAR WHEEL -->
<!-- Center at X: 0, Y: 250, Radius: 60 -->
<g id="rear-wheel" transform="translate(0, 250)">
<!-- Tire -->
<circle cx="0" cy="0" r="60" fill="none" stroke="#1e293b" stroke-width="12" />
<circle cx="0" cy="0" r="56" fill="none" stroke="#f1f5f9" stroke-width="3" />
<circle cx="0" cy="0" r="53" fill="#0f172a" opacity="0.05" />
<!-- Spokes (will be rotated via JS) -->
<g id="rear-spokes">
<line x1="-54" y1="0" x2="54" y2="0" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="0" y1="-54" x2="0" y2="54" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-38" y1="-38" x2="38" y2="38" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-38" y1="38" x2="38" y2="-38" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-50" y1="-20" x2="50" y2="20" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-20" y1="-50" x2="20" y2="50" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-50" y1="20" x2="50" y2="-20" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-20" y1="50" x2="20" y2="-50" stroke="#cbd5e1" stroke-width="1.5" />
</g>
<!-- Hub -->
<circle cx="0" cy="0" r="8" fill="url(#metallic)" stroke="#475569" stroke-width="1.5" />
</g>

<!-- BIKE FRONT WHEEL -->
<!-- Center at X: 240, Y: 250, Radius: 60 -->
<g id="front-wheel" transform="translate(240, 250)">
<!-- Tire -->
<circle cx="0" cy="0" r="60" fill="none" stroke="#1e293b" stroke-width="12" />
<circle cx="0" cy="0" r="56" fill="none" stroke="#f1f5f9" stroke-width="3" />
<circle cx="0" cy="0" r="53" fill="#0f172a" opacity="0.05" />
<!-- Spokes -->
<g id="front-spokes">
<line x1="-54" y1="0" x2="54" y2="0" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="0" y1="-54" x2="0" y2="54" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-38" y1="-38" x2="38" y2="38" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-38" y1="38" x2="38" y2="-38" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-50" y1="-20" x2="50" y2="20" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-20" y1="-50" x2="20" y2="50" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-50" y1="20" x2="50" y2="-20" stroke="#cbd5e1" stroke-width="1.5" />
<line x1="-20" y1="50" x2="20" y2="-50" stroke="#cbd5e1" stroke-width="1.5" />
</g>
<!-- Hub -->
<circle cx="0" cy="0" r="8" fill="url(#metallic)" stroke="#475569" stroke-width="1.5" />
</g>

<!-- BACK LEG & PEDAL (Behind Bike Frame) -->
<g id="back-leg-group">
<!-- Back pedal arm & pedal (drawn via JS IK) -->
<line id="back-crank" x1="110" y1="250" x2="90" y2="225" stroke="#64748b" stroke-width="5" stroke-linecap="round" />
<rect id="back-pedal-rect" x="80" y="220" width="20" height="8" rx="3" fill="#334155" />
<!-- Back leg bones -->
<path id="back-pelican-leg" d="M 85 140 Q 70 190 90 225" fill="none" stroke="#ea580c" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" opacity="0.65" />
<!-- Back Webbed foot -->
<path id="back-pelican-foot" d="M 80 220 L 105 220 L 98 226 L 82 226 Z" fill="#c2410c" opacity="0.65" />
</g>

<!-- BIKE FRAME (Charming Vintage Turquoise Cruiser) -->
<g id="bike-frame" filter="url(#shadow)">
<!-- Mudguards -->
<path d="M -45 210 A 62 62 0 0 1 35 198" fill="none" stroke="#0891b2" stroke-width="7" stroke-linecap="round" />
<path d="M 195 198 A 62 62 0 0 1 275 210" fill="none" stroke="#0891b2" stroke-width="7" stroke-linecap="round" />

<!-- Rear stays -->
<line x1="0" y1="250" x2="70" y2="160" stroke="url(#frame-grad)" stroke-width="8" stroke-linecap="round" />
<line x1="0" y1="250" x2="110" y2="250" stroke="url(#frame-grad)" stroke-width="8" stroke-linecap="round" />

<!-- Seat tube -->
<line x1="70" y1="160" x2="110" y2="250" stroke="url(#frame-grad)" stroke-width="9" stroke-linecap="round" />
<line x1="70" y1="160" x2="62" y2="135" stroke="url(#metallic)" stroke-width="7" stroke-linecap="round" />
<!-- Saddle -->
<path d="M 45 133 C 55 130, 85 130, 92 138 C 88 143, 60 142, 45 133 Z" fill="#78350f" stroke="#451a03" stroke-width="1.5" />
<circle cx="53" cy="138" r="3" fill="#d97706" />

<!-- Down tube and Top curved tube (Cruiser Style) -->
<line x1="110" y1="250" x2="205" y2="145" stroke="url(#frame-grad)" stroke-width="9" stroke-linecap="round" />
<path d="M 70 165 C 120 185, 170 155, 205 145" fill="none" stroke="url(#frame-grad)" stroke-width="8" stroke-linecap="round" />

<!-- Head tube & Fork -->
<line x1="205" y1="145" x2="240" y2="250" stroke="url(#frame-grad)" stroke-width="8" stroke-linecap="round" />
<line x1="205" y1="145" x2="198" y2="115" stroke="url(#metallic)" stroke-width="7" stroke-linecap="round" />

<!-- Handlebars (Cruiser swept back) -->
<path d="M 198 115 Q 185 100, 160 108" fill="none" stroke="url(#metallic)" stroke-width="6" stroke-linecap="round" />
<!-- Hand Grips -->
<rect x="155" y="103" width="14" height="10" rx="3" fill="#78350f" transform="rotate(15 155 103)" />

<!-- Front Bike Basket with a Fish! -->
<g id="bike-basket" transform="translate(195, 115)">
<rect x="0" y="0" width="38" height="28" rx="4" fill="#d97706" stroke="#92400e" stroke-width="1.5" />
<!-- Basket weave lines -->
<line x1="8" y1="0" x2="8" y2="28" stroke="#92400e" stroke-width="1" />
<line x1="18" y1="0" x2="18" y2="28" stroke="#92400e" stroke-width="1" />
<line x1="28" y1="0" x2="28" y2="28" stroke="#92400e" stroke-width="1" />
<line x1="0" y1="10" x2="38" y2="10" stroke="#92400e" stroke-width="1" />
<line x1="0" y1="20" x2="38" y2="20" stroke="#92400e" stroke-width="1" />

<!-- Little happy fish in the basket -->
<g id="basket-fish" transform="translate(18, -2)" style="animation: fish-wiggle 1.2s ease-in-out infinite;">
<path d="M 0 0 C 8 -10, 18 -6, 16 6 C 14 14, 2 12, 0 0 Z" fill="#38bdf8" stroke="#0284c7" stroke-width="1" />
<circle cx="10" cy="-1" r="2.5" fill="#fff" />
<circle cx="11" cy="-1" r="1.2" fill="#0f172a" />
<path d="M 16 6 L 24 2 L 22 10 Z" fill="#0284c7" />
</g>
</g>

<!-- Bicycle Bell -->
<g id="bike-bell-group" transform="translate(182, 104)" style="cursor: pointer;">
<circle cx="0" cy="0" r="7" fill="#fbbf24" stroke="#d97706" stroke-width="1.5" />
<circle cx="-2" cy="-2" r="2" fill="#fef08a" />
<circle id="bell-wave" cx="0" cy="0" r="0" fill="none" stroke="#f59e0b" opacity="0" />
</g>

<!-- Chainwheel / Crankset -->
<circle cx="110" cy="250" r="16" fill="url(#metallic)" stroke="#475569" stroke-width="2" />
<circle cx="110" cy="250" r="8" fill="#1e293b" />
<!-- Bike Chain -->
<path d="M 0 250 L 110 236 A 16 16 0 0 1 110 264 L 0 250" fill="none" stroke="#475569" stroke-width="3" stroke-dasharray="3,2" />
</g>

<!-- PELICAN BODY & HEAD GROUP (Bobbing dynamically with pedal) -->
<g id="pelican-body-group">

<!-- Tail Feathers -->
<path id="pelican-tail" d="M 40 135 C 10 130, -5 145, 8 160 C 25 155, 45 150, 50 145 Z" fill="#94a3b8" />

<!-- Pelican Torso / Body -->
<path id="pelican-torso" d="M 50 120 C 40 150, 60 190, 95 185 C 125 180, 140 145, 125 110 C 115 85, 80 80, 65 100 C 55 108, 52 114, 50 120 Z" fill="url(#feather-grad)" stroke="#cbd5e1" stroke-width="1.5" filter="url(#shadow)" />

<!-- Pelican Neck & Head -->
<g id="pelican-head-neck">
<!-- Curved graceful S-shaped Neck -->
<path d="M 115 115 C 130 90, 145 60, 135 30 C 130 15, 115 20, 120 40 C 122 55, 110 85, 95 105 Z" fill="url(#feather-grad)" stroke="#cbd5e1" stroke-width="1" />

<!-- Head Base -->
<circle cx="138" cy="24" r="16" fill="#ffffff" stroke="#e2e8f0" stroke-width="1" />

<!-- Head Tuft / Feathers on top -->
<path d="M 125 15 Q 115 8, 120 0 Q 130 10, 132 12" fill="#94a3b8" />
<path d="M 128 12 Q 120 3, 128 -4 Q 134 6, 136 10" fill="#cbd5e1" />

<!-- Huge Pelican Pouch (Gular Pouch) & Upper Bill -->
<!-- Giant expressive beak with throat pouch! -->
<g id="pelican-beak" filter="url(#shadow)">
<!-- Throat Pouch (Big stretchy sac) -->
<path id="throat-pouch" d="M 148 28 C 170 38, 205 60, 215 35 C 220 25, 175 25, 150 25 Z" fill="url(#pouch-grad)" stroke="#ea580c" stroke-width="1.5" />
<!-- Pouch muscle texture lines -->
<path d="M 160 30 Q 185 50, 205 32" fill="none" stroke="#f97316" stroke-width="1.2" opacity="0.6" />
<path d="M 170 30 Q 190 44, 200 30" fill="none" stroke="#f97316" stroke-width="1" opacity="0.6" />

<!-- Little Fish poking out of pouch (wiggling tail) -->
<g id="pouch-fish" transform="translate(195, 20) rotate(-15)">
<path d="M 0 0 C 6 -4, 14 -2, 18 4 C 14 8, 4 6, 0 0 Z" fill="#22d3ee" stroke="#0891b2" stroke-width="1" />
<path d="M 18 4 L 25 0 L 23 8 Z" fill="#0891b2" />
</g>

<!-- Upper Long Hooked Bill -->
<path d="M 138 16 L 225 18 C 228 18, 232 20, 230 25 C 228 27, 222 24, 218 22 L 142 24 Z" fill="#f59e0b" stroke="#d97706" stroke-width="1.5" />
<!-- Beak hook tip -->
<path d="M 225 18 Q 232 21, 228 26 Q 224 23, 220 22 Z" fill="#dc2626" />
</g>

<!-- Expressive Eye & Cheek -->
<circle cx="140" cy="20" r="5.5" fill="#fef08a" stroke="#f59e0b" stroke-width="1" />
<circle id="eye-pupil" cx="142" cy="19" r="2.8" fill="#0f172a" />
<circle cx="143" cy="18" r="1" fill="#ffffff" />
<!-- Eye lid (blinking) -->
<ellipse id="eye-lid" cx="140" cy="20" rx="5.5" ry="0" fill="#f8fafc" stroke="#e2e8f0" stroke-width="0.5" />

<!-- Cute Cycling Cap / Visor -->
<g id="cycling-cap">
<path d="M 125 15 C 128 6, 145 6, 150 14 Z" fill="#ef4444" />
<path d="M 142 12 Q 165 8, 172 13 Q 155 16, 142 15 Z" fill="#ffffff" stroke="#e2e8f0" stroke-width="0.5" />
<circle cx="137" cy="8" r="2" fill="#ffffff" />
</g>

<!-- Snazzy Wind Scarf (Fluttering behind) -->
<g id="scarf-group" transform="translate(112, 55)">
<path d="M 0 0 C 10 5, 20 0, 25 -5 L 20 12 C 10 15, 0 10, 0 0 Z" fill="#f43f5e" />
<!-- Scarf trailing tails animated with CSS/JS -->
<g id="scarf-tail" style="transform-origin: 0 0; animation: scarf-flutter 0.6s ease-in-out infinite alternate;">
<path d="M 0 5 C -20 0, -45 -10, -65 0 C -45 10, -20 15, 0 12 Z" fill="#f43f5e" />
<path d="M -10 6 C -25 2, -40 -4, -55 2 C -40 8, -20 12, -10 10 Z" fill="#fb7185" />
<!-- Scarf fringes -->
<line x1="-65" y1="0" x2="-72" y2="-2" stroke="#fda4af" stroke-width="2" />
<line x1="-65" y1="5" x2="-73" y2="4" stroke="#fda4af" stroke-width="2" />
</g>
</g>

</g>

<!-- Pelican Wing (Arm holding handlebar) -->
<g id="pelican-wing">
<!-- Main wing folded on body with wing tip extending to handlebar -->
<path d="M 65 110 C 60 140, 95 165, 120 135 C 130 120, 125 100, 100 100 C 80 100, 70 105, 65 110 Z" fill="#e2e8f0" stroke="#cbd5e1" stroke-width="1.5" />
<!-- Wing feather lines -->
<path d="M 75 125 C 85 145, 110 148, 122 132" fill="none" stroke="#94a3b8" stroke-width="1.2" stroke-dasharray="2,2" />
<path d="M 85 115 C 95 135, 115 136, 125 122" fill="none" stroke="#94a3b8" stroke-width="1.2" stroke-dasharray="2,2" />

<!-- Wing Arm grasping Handlebar -->
<path id="wing-arm" d="M 105 115 Q 135 120, 160 108" fill="none" stroke="#f1f5f9" stroke-width="10" stroke-linecap="round" />
<path d="M 105 115 Q 135 120, 160 108" fill="none" stroke="#cbd5e1" stroke-width="2" stroke-linecap="round" />
<!-- Feather fingers gripping handlebar -->
<ellipse cx="160" cy="108" rx="6" ry="4" fill="#e2e8f0" stroke="#cbd5e1" stroke-width="1" transform="rotate(-15 160 108)" />
</g>

</g>

<!-- FRONT LEG & PEDAL (In Foreground, connected to Crank) -->
<g id="front-leg-group">
<!-- Front Crank Arm & Pedal (Position calculated dynamically by JS) -->
<line id="front-crank" x1="110" y1="250" x2="130" y2="275" stroke="#475569" stroke-width="6" stroke-linecap="round" />
<circle cx="110" cy="250" r="5" fill="#f8fafc" />
<rect id="front-pedal-rect" x="120" y="270" width="22" height="9" rx="3" fill="#1e293b" stroke="#94a3b8" stroke-width="1" />

<!-- Front Leg & Big Webbed Foot -->
<!-- Pelican Thigh & Shin with IK / Joint curve -->
<path id="front-pelican-leg" d="M 95 150 Q 115 210, 130 275" fill="none" stroke="#f97316" stroke-width="8" stroke-linecap="round" stroke-linejoin="round" />

<!-- Big Orange Webbed Foot -->
<g id="front-pelican-foot" transform="translate(130, 275)">
<!-- Webbing -->
<path d="M -12 -3 L 18 -3 L 12 7 L -8 7 Z" fill="#ea580c" stroke="#c2410c" stroke-width="1" />
<!-- Claws / Toes -->
<line x1="-10" y1="5" x2="-8" y2="8" stroke="#7c2d12" stroke-width="2" stroke-linecap="round" />
<line x1="2" y1="5" x2="4" y2="9" stroke="#7c2d12" stroke-width="2" stroke-linecap="round" />
<line x1="14" y1="5" x2="16" y2="8" stroke="#7c2d12" stroke-width="2" stroke-linecap="round" />
</g>
</g>

</g>
</svg>
</div>

<script>
// ================= DYNAMIC ANIMATION & INTERACTION ENGINE =================

// State
let speed = 28; // km/h
let targetSpeed = 28;
let crankAngle = 0; // In radians
let wheelAngle = 0; // In degrees
let timeThemeIndex = 0; // 0: day, 1: sunset, 2: night
const themes = ['', 'sunset', 'night'];

// DOM Elements
const rearSpokes = document.getElementById('rear-spokes');
const frontSpokes = document.getElementById('front-spokes');
const frontCrank = document.getElementById('front-crank');
const backCrank = document.getElementById('back-crank');
const frontPedalRect = document.getElementById('front-pedal-rect');
const backPedalRect = document.getElementById('back-pedal-rect');
const frontPelicanLeg = document.getElementById('front-pelican-leg');
const backPelicanLeg = document.getElementById('back-pelican-leg');
const frontPelicanFoot = document.getElementById('front-pelican-foot');
const backPelicanFoot = document.getElementById('back-pelican-foot');
const pelicanBodyGroup = document.getElementById('pelican-body-group');
const throatPouch = document.getElementById('throat-pouch');
const eyeLid = document.getElementById('eye-lid');
const speedVal = document.getElementById('speed-val');
const btnSpeed = document.getElementById('btn-speed');
const btnBell = document.getElementById('btn-bell');
const btnTheme = document.getElementById('btn-theme');
const bikeBellGroup = document.getElementById('bike-bell-group');

// Scenery container elements
const mountainsFar = document.getElementById('mountains-far');
const seaRipples = document.getElementById('sea-ripples');
const hillsMid = document.getElementById('hills-mid');
const cloudsLayer = document.getElementById('clouds-layer');
const roadLines = document.getElementById('road-lines');
const roadsideDetails = document.getElementById('roadside-details');
const windParticles = document.getElementById('wind-particles');

// Create Parallax Assets
function initParallaxWorld() {
// 1. Far Mountains
let mountainSvg = '';
for (let i = 0; i < 4; i++) {
const x = i * 400;
mountainSvg += `<polygon points="${x-50},480 ${x+160},280 ${x+380},480" fill="var(--hill-1)" opacity="0.6"/>`;
mountainSvg += `<polygon points="${x+120},480 ${x+280},320 ${x+450},480" fill="var(--hill-2)" opacity="0.5"/>`;
}
mountainsFar.innerHTML = mountainSvg;

// 2. Mid Hills with trees
let hillSvg = '';
for (let i = 0; i < 6; i++) {
const x = i * 260;
hillSvg += `<path d="M ${x-40} 490 Q ${x+100} 410 ${x+240} 490 Z" fill="var(--grass-dark)" opacity="0.75"/>`;
// Tree
hillSvg += `<circle cx="${x+80}" cy="425" r="18" fill="#15803d" opacity="0.9"/>`;
hillSvg += `<circle cx="${x+95}" cy="420" r="14" fill="#22c55e" opacity="0.8"/>`;
}
hillsMid.innerHTML = hillSvg;

// 3. Clouds
let cloudSvg = '';
const cloudData = [
{ x: 100, y: 70, s: 1 },
{ x: 450, y: 110, s: 0.75 },
{ x: 800, y: 60, s: 1.2 },
{ x: 1150, y: 95, s: 0.85 }
];
cloudData.forEach(c => {
cloudSvg += `
<g class="cloud-item" data-speed="0.3" transform="translate(${c.x}, ${c.y}) scale(${c.s})">
<path d="M 0 20 C -10 20 -20 10 -15 0 C -10 -12 10 -15 20 -5 C 28 -20 52 -18 58 -2 C 70 -5 80 8 75 20 Z" fill="#ffffff" opacity="0.85" />
</g>
`;
});
cloudsLayer.innerHTML = cloudSvg;

// 4. Road dashed lines
let linesSvg = '';
for (let i = 0; i < 15; i++) {
linesSvg += `<rect class="road-dash" x="${i * 100}" y="615" width="55" height="8" rx="4" fill="var(--road-line)" opacity="0.85"/>`;
}
roadLines.innerHTML = linesSvg;

// 5. Roadside bushes and flowers
let detailsSvg = '';
for (let i = 0; i < 10; i++) {
const x = i * 140;
detailsSvg += `
<g class="road-item" data-x="${x}">
<circle cx="${x}" cy="535" r="10" fill="#4ade80" />
<circle cx="${x+12}" cy="532" r="8" fill="#22c55e" />
<circle cx="${x+6}" cy="528" r="4" fill="#f43f5e" />
</g>
`;
}
roadsideDetails.innerHTML = detailsSvg;

// 6. Wind particles
let windSvg = '';
for (let i = 0; i < 8; i++) {
windSvg += `<line class="wind-line" x1="0" y1="0" x2="50" y2="0" stroke="#ffffff" stroke-width="2" stroke-linecap="round" opacity="0.4"/>`;
}
windParticles.innerHTML = windSvg;
}

initParallaxWorld();

// Wind particles animation state
const winds = Array.from({ length: 8 }, () => ({
x: Math.random() * 1200,
y: 100 + Math.random() * 450,
len: 30 + Math.random() * 60,
speed: 1.5 + Math.random() * 1.5
}));

// Audio synthesizer for Bicycle Bell chime (Web Audio API)
let audioCtx = null;
function playBellSound() {
try {
if (!audioCtx) {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
}
if (audioCtx.state === 'suspended') {
audioCtx.resume();
}

const now = audioCtx.currentTime;
const freqs = [2093, 2500, 3135]; // High crisp bell tones

freqs.forEach((freq, idx) => {
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(freq, now + idx * 0.08);

gain.gain.setValueAtTime(0.25, now + idx * 0.08);
gain.gain.exponentialRampToValueAtTime(0.001, now + idx * 0.08 + 0.6);

osc.connect(gain);
gain.connect(audioCtx.destination);

osc.start(now + idx * 0.08);
osc.stop(now + idx * 0.08 + 0.65);
});

// Trigger visual ripple
triggerBellVisual();
} catch (e) {
triggerBellVisual();
}
}

function triggerBellVisual() {
const bellGroup = document.getElementById('pelican-cyclist');
const wave = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
wave.setAttribute('cx', '182');
wave.setAttribute('cy', '104');
wave.setAttribute('class', 'bell-sound-wave');
wave.setAttribute('fill', 'none');
wave.setAttribute('stroke', '#fbbf24');
bellGroup.appendChild(wave);
setTimeout(() => wave.remove(), 800);
}

// Inverse Kinematics / Trigonometric Leg solver for Pelican
// Hip: (95, 140), Crank Center: (110, 250), Crank Radius: 30
function updatePelicanLegs(angle, bodyBobY) {
const hipX = 95;
const hipY = 145 + bodyBobY;
const crankCenter = { x: 110, y: 250 };
const crankLength = 28;

// --- Front Leg & Pedal ---
const frontPedalX = crankCenter.x + Math.cos(angle) * crankLength;
const frontPedalY = crankCenter.y + Math.sin(angle) * crankLength;

frontCrank.setAttribute('x1', crankCenter.x);
frontCrank.setAttribute('y1', crankCenter.y);
frontCrank.setAttribute('x2', frontPedalX);
frontCrank.setAttribute('y2', frontPedalY);

frontPedalRect.setAttribute('x', frontPedalX - 11);
frontPedalRect.setAttribute('y', frontPedalY - 4);

// Knee bending position (midway with forward knee curve)
const frontKneeX = (hipX + frontPedalX) / 2 + 25 + Math.sin(angle) * 10;
const frontKneeY = (hipY + frontPedalY) / 2 - 10;

frontPelicanLeg.setAttribute('d', `M ${hipX} ${hipY} Q ${frontKneeX} ${frontKneeY} ${frontPedalX} ${frontPedalY}`);
frontPelicanFoot.setAttribute('transform', `translate(${frontPedalX}, ${frontPedalY}) rotate(${Math.sin(angle) * 15})`);

// --- Back Leg & Pedal (180 deg / PI out of phase) ---
const backAngle = angle + Math.PI;
const backPedalX = crankCenter.x + Math.cos(backAngle) * crankLength;
const backPedalY = crankCenter.y + Math.sin(backAngle) * crankLength;

backCrank.setAttribute('x1', crankCenter.x);
backCrank.setAttribute('y1', crankCenter.y);
backCrank.setAttribute('x2', backPedalX);
backCrank.setAttribute('y2', backPedalY);

backPedalRect.setAttribute('x', backPedalX - 10);
backPedalRect.setAttribute('y', backPedalY - 4);

const backKneeX = (hipX - 10 + backPedalX) / 2 + 18 + Math.sin(backAngle) * 10;
const backKneeY = (hipY + backPedalY) / 2 - 12;

backPelicanLeg.setAttribute('d', `M ${hipX - 10} ${hipY} Q ${backKneeX} ${backKneeY} ${backPedalX} ${backPedalY}`);
backPelicanFoot.setAttribute('transform', `translate(${backPedalX - 90}, ${backPedalY - 225})`);
}

// Blinking eye simulation
let blinkTimer = 0;
function updateEyeBlink(deltaTime) {
blinkTimer += deltaTime;
if (blinkTimer > 3.5) {
eyeLid.setAttribute('ry', '5.5');
if (blinkTimer > 3.65) {
eyeLid.setAttribute('ry', '0');
blinkTimer = 0;
}
}
}

// Parallax positions
let mountainOffset = 0;
let hillOffset = 0;
let roadOffset = 0;
let cloudOffset = 0;

// Main Animation Loop
let lastTime = performance.now();

function animate(currentTime) {
const deltaMs = currentTime - lastTime;
const dt = Math.min(deltaMs / 1000, 0.1);
lastTime = currentTime;

// Smooth speed easing
speed += (targetSpeed - speed) * 0.05;
speedVal.textContent = Math.round(speed);

const speedFactor = speed / 28;

// 1. Rotate Wheels & Spokes
wheelAngle = (wheelAngle + speedFactor * 420 * dt) % 360;
rearSpokes.setAttribute('transform', `rotate(${wheelAngle})`);
frontSpokes.setAttribute('transform', `rotate(${wheelAngle})`);

// 2. Pedaling cadence (Crank rotation)
crankAngle = (crankAngle + speedFactor * 4.5 * dt) % (Math.PI * 2);

// 3. Pelican Body Bobbing (Rhythmic bounce matching pedaling effort)
const bodyBobY = Math.sin(crankAngle * 2) * 3.5;
const bodyRot = Math.cos(crankAngle) * 1.5;
pelicanBodyGroup.setAttribute('transform', `translate(0, ${bodyBobY}) rotate(${bodyRot} 110 160)`);

// 4. Throat pouch slight wobbling
const pouchStretch = Math.sin(crankAngle * 2 + 1) * 2;
throatPouch.setAttribute('d', `M 148 28 C 170 ${38 + pouchStretch}, 205 ${60 + pouchStretch * 1.5}, 215 35 C 220 25, 175 25, 150 25 Z`);

// 5. Update Legs to stay locked to Pedals
updatePelicanLegs(crankAngle, bodyBobY);

// 6. Blinking eyes
updateEyeBlink(dt);

// 7. Parallax Scrolling of scenery
// Far mountains
mountainOffset = (mountainOffset - speedFactor * 30 * dt) % 400;
mountainsFar.setAttribute('transform', `translate(${mountainOffset}, 0)`);

// Mid hills
hillOffset = (hillOffset - speedFactor * 90 * dt) % 260;
hillsMid.setAttribute('transform', `translate(${hillOffset}, 0)`);

// Road dash lines
roadOffset = (roadOffset - speedFactor * 400 * dt) % 100;
roadLines.setAttribute('transform', `translate(${roadOffset}, 0)`);

// Roadside bushes
const roadsideItems = roadsideDetails.querySelectorAll('.road-item');
roadsideItems.forEach(item => {
let curX = parseFloat(item.getAttribute('data-x'));
curX -= speedFactor * 350 * dt;
if (curX < -60) curX += 1400;
item.setAttribute('data-x', curX);
item.setAttribute('transform', `translate(${curX - parseFloat(item.querySelector('circle').getAttribute('cx'))}, 0)`);
});

// Clouds
const cloudElems = cloudsLayer.querySelectorAll('.cloud-item');
cloudElems.forEach((cloud, idx) => {
let x = (idx * 320 - currentTime * 0.02 * (idx + 1)) % 1400;
if (x < -150) x += 1400;
cloud.setAttribute('transform', `translate(${x}, ${60 + idx * 25}) scale(${0.8 + idx * 0.15})`);
});

// 8. Wind Particles
const windLines = windParticles.querySelectorAll('.wind-line');
winds.forEach((w, i) => {
w.x -= (speedFactor * 600 * w.speed) * dt;
if (w.x < -100) {
w.x = 1250 + Math.random() * 200;
w.y = 80 + Math.random() * 480;
}
if (windLines[i]) {
windLines[i].setAttribute('x1', w.x);
windLines[i].setAttribute('y1', w.y);
windLines[i].setAttribute('x2', w.x + w.len * (speedFactor * 0.8));
windLines[i].setAttribute('y2', w.y);
windLines[i].setAttribute('opacity', Math.min(0.7, 0.15 * speedFactor));
}
});

requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

// ================= INTERACTION HANDLERS =================

// Speed boost toggle / sprint
let isSprinting = false;
function toggleSprint() {
isSprinting = !isSprinting;
if (isSprinting) {
targetSpeed = 54;
btnSpeed.innerHTML = '💨 巡航';
btnSpeed.style.background = '#fde047';
} else {
targetSpeed = 28;
btnSpeed.innerHTML = '⚡ 加速';
btnSpeed.style.background = '';
}
}

btnSpeed.addEventListener('click', toggleSprint);

// Bell chime button & click on bicycle bell
btnBell.addEventListener('click', playBellSound);
bikeBellGroup.addEventListener('click', playBellSound);

// Theme Switcher (Day -> Sunset -> Night)
btnTheme.addEventListener('click', () => {
timeThemeIndex = (timeThemeIndex + 1) % themes.length;
document.body.className = themes[timeThemeIndex];
const icons = ['🌅 傍晚', '🌙 夜晚', '☀️ 白天'];
btnTheme.innerHTML = icons[timeThemeIndex];
});

// Keyboard shortcuts
window.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
e.preventDefault();
toggleSprint();
} else if (e.code === 'KeyB') {
playBellSound();
}
});
</script>
</body>
</html>

最新回复 (9)
  • 佬友记 08-19 00:53
    1

    目前见过的最好的版本,比grok的还要好

  • DIAVE971 08-19 00:54
    2

    佬是使用反代的api吗?用的是啥工具啊,求指路

  • 紫米 楼主 08-19 00:55
    3

    tg随便搜的一个中转站,大概率是反重力反代

  • liansishen 08-19 00:56
    4

    今天刚买了个反重力pro,折腾了好久终于用上了,希望能撑久一点

  • zlflly 08-19 01:00
    5

    佬友用的什么harness哇,感觉很简洁很不错

  • tuozhwei 08-19 01:00
    6

    难道现在的AI是轮流坐庄吗,Gemini又雄起了?

  • 紫米 楼主 08-19 01:00
    7

    deepseek harness 自己装了些插件

  • mmmmmly 08-19 01:03
    8

    这个看着真不错啊,比我网页版的gpt-5.6-sol画的都好了

  • catnap 08-19 01:17
    9



    我的pro反代,脚蹬子那里拉了

* 帖子来源Linux.do
返回