astra max 鹈鹕测试 不降智
qianye
2026-09-07 09:29
1

展开查看完整 HTML 源码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#f6f4ec">
<title>顺风,出发。 · 鹈鹕骑行记</title>
<style>
:root {
color-scheme: light;
--paper: #f6f4ec;
--ink: #304a41;
--muted: #788477;
--green: #35695b;
--coral: #db8065;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100svh;
background: var(--paper);
color: var(--ink);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
-webkit-font-smoothing: antialiased;
}
button, input { font: inherit; }
button { -webkit-tap-highlight-color: transparent; }
button:focus-visible, input:focus-visible {
outline: 3px solid #dc9b55;
outline-offset: 5px;
}
.page { width: min(1120px, calc(100% - 80px)); margin: 0 auto; padding: 44px 0 26px; }
.masthead { display: flex; justify-content: space-between; align-items: center; gap: 20px; }
.brand { display: flex; align-items: center; gap: 10px; font-size: 11px; letter-spacing: 2.1px; font-weight: 650; }
.brand-mark { width: 26px; height: 26px; color: var(--green); }
.edition { font-size: 10px; letter-spacing: 1.8px; color: var(--muted); }
.intro { display: flex; justify-content: space-between; align-items: end; gap: 24px; margin: 35px 0 25px; }
h1 {
margin: 0 0 13px;
font-family: "Songti SC", "Noto Serif CJK SC", "STSong", serif;
font-size: clamp(32px, 4.3vw, 48px);
font-weight: 600;
letter-spacing: 2px;
line-height: 1.25;
}
.intro p { margin: 0; font-size: 13px; color: #768174; letter-spacing: 1px; line-height: 1.8; }
.little-note { display: flex; align-items: center; gap: 9px; font-size: 11px; color: #7c8777; white-space: nowrap; padding-bottom: 3px; }
.little-note::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: #df9c64; }
.illustration { overflow: hidden; border-radius: 22px; border: 1px solid #dfe3d5; background: #edf0e1; box-shadow: 0 12px 30px -24px #344d413b; }
#scene { width: 100%; height: auto; display: block; }
.controls { min-height: 83px; display: flex; align-items: center; gap: 24px; padding: 17px 27px; background: #fcfbf5; border-top: 1px solid #e2e4d6; }
.play-button { display: inline-flex; justify-content: center; align-items: center; gap: 9px; background: var(--green); color: #fffdf3; border: 0; border-radius: 100px; min-width: 104px; height: 42px; padding: 0 21px; cursor: pointer; font-size: 12px; letter-spacing: 1px; transition: background .2s, transform .2s; }
.play-button:hover { background: #284f44; transform: translateY(-1px); }
.icon { display: block; width: 16px; height: 16px; flex-shrink: 0; }
.speed-control { display: flex; align-items: center; gap: 13px; font-size: 11px; }
.speed-control label { color: #6f7d70; white-space: nowrap; }
#speed { width: 125px; height: 4px; margin: 0; accent-color: var(--green); cursor: pointer; }
#speed-value { min-width: 35px; color: var(--green); font-size: 11px; font-variant-numeric: tabular-nums; }
.control-end { margin-left: auto; display: flex; align-items: center; gap: 20px; }
.riding-status { display: flex; align-items: center; gap: 7px; font-size: 11px; color: #7b8775; white-space: nowrap; }
.status-dot { width: 5px; height: 5px; border-radius: 50%; background: #819d69; }
body[data-paused="true"] .status-dot { background: #c1aa83; }
.bell-button { display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 15px; border: 1px solid #dfe3d4; border-radius: 100px; color: var(--ink); background: transparent; font-size: 11px; cursor: pointer; transition: background .2s, border-color .2s; white-space: nowrap; }
.bell-button:hover { background: #f0efdf; border-color: #cdd4bf; }
footer { display: flex; justify-content: space-between; gap: 15px; padding: 22px 3px 0; font-size: 10px; letter-spacing: 1.1px; color: #959d8d; }
.footer-caption { color: #7e8a79; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
@media (min-width: 1500px) { .page { padding-top: 64px; } }
@media (max-width: 700px) {
.page { width: calc(100% - 32px); padding-top: 25px; }
.edition { font-size: 8px; letter-spacing: 1px; }
.brand { font-size: 9px; letter-spacing: 1.4px; }
.intro { margin: 29px 0 20px; }
.intro p { font-size: 11px; letter-spacing: .2px; }
.little-note { display: none; }
.illustration { border-radius: 17px; }
#scene { height: clamp(300px, 66vw, 465px); }
.controls { flex-wrap: wrap; gap: 17px 20px; padding: 18px; }
.play-button { min-width: 91px; height: 39px; padding: 0 16px; }
.speed-control { margin-left: auto; gap: 9px; }
#speed { width: clamp(67px, 17vw, 110px); }
.speed-control label { font-size: 10px; }
.control-end { flex-basis: 100%; justify-content: space-between; }
.bell-button { height: 34px; }
footer { font-size: 9px; letter-spacing: .4px; padding-top: 19px; }
}
@media (prefers-reduced-motion: reduce) { button { transition: none !important; } }
</style>
</head>
<body data-paused="false">
<main class="page">
<header class="masthead">
<div class="brand">
<svg class="brand-mark" viewBox="0 0 30 30" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<circle cx="8" cy="21" r="5.5"/><circle cx="23" cy="21" r="5.5"/>
<path d="m8 21 5-10 5 10H8l12-10 3 10M11 11h5m2-4h3l1 4"/>
<path d="M6 6h4M4 10h4" opacity=".5"/>
</svg>
PELICAN RIDING CLUB
</div>
<span class="edition">A LITTLE JOY, ON TWO WHEELS</span>
</header>
<div class="intro">
<div><h1>顺风,出发。</h1><p>一只鹈鹕,一辆单车,一整天的好心情。</p></div>
<div class="little-note">不赶路,感受路。</div>
</div>
<section class="illustration" aria-label="鹈鹕海边骑行的 SVG 动画">
<svg id="scene" viewBox="0 0 1200 650" preserveAspectRatio="xMidYMid slice" role="img" aria-labelledby="scene-title scene-description" xmlns="http://www.w3.org/2000/svg">
<title id="scene-title">鹈鹕的海边骑行日</title>
<desc id="scene-description">一只戴珊瑚色骑行帽、系红围巾的白色鹈鹕,在海边骑着绿色自行车。脚蹼随着脚踏转动,车轮滚动,围巾和车后篮子里的雏菊随风摇摆,远处的云朵和山丘缓缓经过。</desc>
<defs>
<linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"><stop stop-color="#eaf0e3"/><stop offset="1" stop-color="#f5f2de"/></linearGradient>
<linearGradient id="pouch" x1="0" y1="0" x2="0.4" y2="1"><stop stop-color="#f6cb80"/><stop offset="1" stop-color="#e9ad70"/></linearGradient>
<linearGradient id="feather" x1="0" y1="0" x2="0.2" y2="1"><stop stop-color="#fffef2"/><stop offset="1" stop-color="#eeefdd"/></linearGradient>
<pattern id="paper-grain" width="120" height="110" patternUnits="userSpaceOnUse">
<circle cx="8" cy="19" r=".7" fill="#52614c" opacity=".09"/><circle cx="69" cy="80" r=".8" fill="#52614c" opacity=".07"/>
<circle cx="49" cy="34" r=".6" fill="#fffdf3" opacity=".7"/><circle cx="108" cy="53" r=".9" fill="#fffdf3" opacity=".5"/>
<path d="m24 91 2 1m72-78 2-1" stroke="#52614c" stroke-width=".6" opacity=".08"/>
</pattern>
<g id="cloud" fill="#fffdf0">
<path d="M0 34C-4 21 8 13 24 16 26-1 50-5 61 9 74 3 89 12 89 24 109 23 118 31 113 38H4Z"/>
</g>
<g id="daisy" stroke="#ececda" stroke-width=".9">
<ellipse cy="-8" rx="4" ry="7" fill="#fffdf2"/>
<ellipse cy="-8" rx="4" ry="7" fill="#fffdf2" transform="rotate(60)"/>
<ellipse cy="-8" rx="4" ry="7" fill="#fffdf2" transform="rotate(120)"/>
<ellipse cy="-8" rx="4" ry="7" fill="#fffdf2" transform="rotate(180)"/>
<ellipse cy="-8" rx="4" ry="7" fill="#fffdf2" transform="rotate(240)"/>
<ellipse cy="-8" rx="4" ry="7" fill="#fffdf2" transform="rotate(300)"/>
<circle r="4.9" fill="#e9b85d" stroke="none"/>
</g>
<g id="wheel" fill="none" stroke-linecap="round">
<circle r="76" fill="#f8f4e7" fill-opacity=".4" stroke="#344c43" stroke-width="9"/>
<circle r="70" stroke="#f9f4e4" stroke-width="3"/>
<circle r="65" stroke="#93a59b" stroke-width="1.5"/>
<g stroke="#90a398" stroke-width="1.6">
<path d="M-65 0H65M0-65V65M-56.29-32.5 56.29 32.5M-32.5-56.29 32.5 56.29M32.5-56.29-32.5 56.29M56.29-32.5-56.29 32.5"/>
</g>
<circle r="9" fill="#e6e6d5" stroke="#3d6253" stroke-width="3"/>
<path d="M-44-52A68 68 0 0 1-18-66" stroke="#fffbee" stroke-width="3"/>
<path d="M-3-49H3" stroke="#e5af67" stroke-width="7"/>
</g>
<g id="grass" fill="none" stroke="#829573" stroke-width="3" stroke-linecap="round">
<path d="M0 0Q-1-25-10-35M0 0Q5-33 17-46M0 0Q13-18 25-21M0 0Q-10-17-24-19"/>
<path d="M17-46q-3-10 6-15" stroke="#b9aa78" stroke-width="5"/>
</g>
<g id="road-tile">
<path d="M30 576h71m151 0h71m151 0h71" stroke="#f8f4e2" stroke-width="5" stroke-linecap="round"/>
<g fill="#b5b49a" opacity=".65"><ellipse cx="82" cy="544" rx="3.5" ry="1.4"/><ellipse cx="209" cy="603" rx="2.7" ry="1.2"/><ellipse cx="342" cy="535" rx="2" ry="1"/><ellipse cx="520" cy="613" rx="4" ry="1.2"/><ellipse cx="561" cy="550" rx="2" ry="1.2"/></g>
<path d="M133 623h11m246-74h8" stroke="#c2bfa2" stroke-width="1.8" stroke-linecap="round"/>
</g>
<g id="hill-tile">
<path d="M0 413C100 400 138 321 264 337S428 418 590 374 788 319 937 367 1122 396 1200 413V477H0Z" fill="#cbd7bb"/>
<path d="M0 429C128 411 196 393 282 402S434 444 556 418 721 371 843 398 1038 455 1200 429V483H0Z" fill="#b4c9af"/>
</g>
<g id="wave-tile" fill="none" stroke="#e4efe0" stroke-linecap="round">
<path d="M35 447h66m43 14h29m69-20h98m107 17h60m39-13h18" stroke-width="2"/>
<path d="M72 473h29m116 2h74m103-7h43m117 6h29" stroke-width="1.5" opacity=".6"/>
</g>
</defs>
<!-- The scenery moves at different speeds to create parallax. -->
<rect width="1200" height="650" fill="url(#sky)"/>
<g id="sun" transform="translate(948 126)">
<circle r="64" fill="#f2d7a0" opacity=".25"/>
<circle r="47" fill="#ebc17f"/>
<circle r="54" fill="none" stroke="#e9c990" stroke-width="1" opacity=".6"/>
</g>
<g id="cloud-a" opacity=".9"><use href="#cloud" transform="translate(122 96) scale(1.4)"/></g>
<g id="cloud-b" opacity=".75"><use href="#cloud" transform="translate(745 69) scale(.86)"/></g>
<g id="cloud-c" opacity=".6"><use href="#cloud" transform="translate(1046 243) scale(1.18)"/></g>
<g id="distant-birds" fill="none" stroke="#8eaa9a" stroke-width="2.2" stroke-linecap="round">
<path id="sky-bird-a" d="M339 169q9-9 18 0 9-9 18 0"/>
<path id="sky-bird-b" d="M300 189q6-6 12 0 6-6 12 0"/>
<path id="sky-bird-c" d="M1044 185q7-7 14 0 7-7 14 0"/>
</g>
<path d="M0 413Q153 386 286 414T571 411 861 409 1200 409V493H0Z" fill="#d6dfc6"/>
<g id="hills"><use href="#hill-tile"/><use href="#hill-tile" x="1200"/></g>
<path d="M0 431Q245 425 433 438T837 433 1200 438V507H0Z" fill="#a9c9bd"/>
<g id="waves"><use href="#wave-tile"/><use href="#wave-tile" x="600"/><use href="#wave-tile" x="1200"/></g>
<path d="M0 491C163 474 232 493 346 492S572 475 737 491 987 488 1200 479V550H0Z" fill="#e1ddbb"/>
<path d="M0 511C153 493 339 516 507 503S862 515 1200 500" fill="none" stroke="#f0eacf" stroke-width="4"/>
<g id="dune-grass" opacity=".75">
<use href="#grass" transform="translate(114 508) scale(.7)"/>
<use href="#grass" transform="translate(1034 503) scale(.65)"/>
<use href="#grass" transform="translate(663 506) scale(.4)"/>
<use href="#grass" transform="translate(1514 508) scale(.7)"/>
<use href="#grass" transform="translate(2434 503) scale(.65)"/>
<use href="#grass" transform="translate(2063 506) scale(.4)"/>
</g>
<path d="M0 528Q346 522 646 528T1200 526V650H0Z" fill="#d9d4b9"/>
<path d="M0 531Q346 525 646 531T1200 529" fill="none" stroke="#bfc5a4" stroke-width="2"/>
<g id="road"><use href="#road-tile"/><use href="#road-tile" x="666"/><use href="#road-tile" x="1332"/></g>
<ellipse id="cycle-shadow" cx="576" cy="552" rx="228" ry="13" fill="#6d8166" opacity=".16"/>
<!-- All bicycle and rider coordinates share the same local space. -->
<g id="ride" stroke-linecap="round" stroke-linejoin="round">
<g id="back-leg" fill="none">
<path id="back-leg-outline" d="M500 358 564 385 531 454" stroke="#aa753f" stroke-width="14"/>
<path id="back-leg-fill" d="M500 358 564 385 531 454" stroke="#cc964e" stroke-width="9"/>
</g>
<path id="back-crank" d="M565 465 538 465" fill="none" stroke="#819183" stroke-width="6"/>
<g id="back-foot" transform="translate(538 465)">
<path d="M-9-10Q-13-2-10 1L20 1Q25-1 19-5L10-12 6-7 1-13-2-8Z" fill="#d7a04f" stroke="#aa753f" stroke-width="2"/>
<path d="M-13 5h33" stroke="#435b4d" stroke-width="6"/>
</g>
<!-- Wheels rotate independently of their fixed axle positions. -->
<g transform="translate(435 472)"><g id="rear-wheel"><use href="#wheel"/></g></g>
<g transform="translate(724 472)"><g id="front-wheel"><use href="#wheel"/></g></g>
<g fill="none">
<path d="M353 460A84 84 0 0 1 507 430M647 439A84 84 0 0 1 806 457" stroke="#456d5b" stroke-width="11"/>
<path d="M353 458A84 84 0 0 1 505 428M649 436A84 84 0 0 1 806 454" stroke="#a2b7a0" stroke-width="5"/>
<path d="M435 472 403 391M435 472 460 391M378 391H470" stroke="#799381" stroke-width="4"/>
<path d="M435 472 500 379 565 465 435 472M500 379 662 374 565 465M656 351 671 391 724 472" stroke="#365e50" stroke-width="13"/>
<path d="M435 472 500 379 565 465 435 472M500 379 662 374 565 465M656 351 671 391 724 472" stroke="#5b927b" stroke-width="8"/>
<path d="M505 380 652 376M446 458 499 387M674 398 717 465" stroke="#96b59a" stroke-width="2.3"/>
<path d="M499 379 492 360" stroke="#718577" stroke-width="7"/>
<path d="M658 352 669 323Q672 314 683 316L706 321Q714 323 712 331" stroke="#647c6d" stroke-width="7"/>
<path d="m695 319 12 3q7 2 5 9" stroke="#765744" stroke-width="9"/>
<path d="M704 330Q693 346 683 355T695 402" stroke="#809180" stroke-width="1.7"/>
</g>
<path d="M474 356Q490 353 513 356Q519 357 517 363Q516 368 505 368H478Q469 367 471 362Z" fill="#785b49" stroke="#4d5745" stroke-width="2"/>
<path d="M479 358h29" stroke="#b69572" stroke-width="2"/>
<path d="M435 458 565 443C594 443 596 485 566 486L435 483C417 483 416 460 435 458Z" fill="#bfc8ac" stroke="#587d65" stroke-width="2.5"/>
<path d="M438 464 562 450" fill="none" stroke="#dce0c3" stroke-width="2"/>
<circle cx="565" cy="465" r="17" fill="#e0ddc4" stroke="#6f8d76" stroke-width="3"/>
<circle cx="435" cy="472" r="6" fill="#5c7d69"/>
<path d="m564 389 29-1" stroke="#e6ebd5" stroke-width="3"/>
<path d="m568 395 16-.5" stroke="#e6ebd5" stroke-width="1.5" opacity=".6"/>
<!-- A little wicker basket and a moving bouquet on the rear rack. -->
<g id="flowers">
<g fill="none" stroke="#6e9473" stroke-width="2.4">
<path d="M401 362Q407 337 398 311M408 364Q416 342 426 322M394 364Q391 345 379 334"/>
</g>
<g fill="#8ba578"><path d="M402 340Q390 342 388 332 400 329 402 340M412 349Q429 347 431 337 417 335 412 349M394 352Q380 350 379 342 392 341 394 352"/></g>
<use href="#daisy" transform="translate(397 310) rotate(-13)"/>
<use href="#daisy" transform="translate(428 320) scale(.8) rotate(12)"/>
<use href="#daisy" transform="translate(377 332) scale(.72)"/>
</g>
<path d="M369 351H441L433 387Q402 394 376 384Z" fill="#d6ad76" stroke="#947c54" stroke-width="2"/>
<path d="M372 360h66m-64 10h62m-60 9h57M380 354l5 32m7-32 2 35m11-35v36m12-36-2 34m14-34-5 33" stroke="#b18d5f" stroke-width="1.4" fill="none"/>
<path d="M369 352H441" stroke="#e2c18f" stroke-width="6"/>
<path d="M379 349v37m50-37-4 39" stroke="#907653" stroke-width="3"/>
<path id="front-crank" d="M565 465 592 465" fill="none" stroke="#546f5b" stroke-width="7"/>
<path id="front-crank-shine" d="M565 465 592 465" fill="none" stroke="#bac6ad" stroke-width="3"/>
<g id="front-leg" fill="none">
<path id="front-leg-outline" d="M518 361 582 398 585 454" stroke="#b88146" stroke-width="15"/>
<path id="front-leg-fill" d="M518 361 582 398 585 454" stroke="#e5ac59" stroke-width="10"/>
</g>
<g id="front-foot" transform="translate(592 465)">
<path d="M-9-10Q-13-2-10 1L20 1Q25-1 19-5L10-12 6-7 1-13-2-8Z" fill="#efb95e" stroke="#b88146" stroke-width="2"/>
<path d="m1-4 5 3m4-4 4 3" stroke="#cd9149" stroke-width="1.2"/>
<path d="M-13 5h33" stroke="#3e584b" stroke-width="6"/>
<path d="M-7 4H13" stroke="#8b9b81" stroke-width="1.4"/>
</g>
<circle cx="565" cy="465" r="5" fill="#46634f"/>
<g id="pelican-body">
<path id="scarf-tail" d="M550 262C523 260 511 243 485 248L445 244 457 257 442 267C483 259 513 287 551 277Z" fill="#d98267" stroke="#bc7059" stroke-width="1.7"/>
<path id="scarf-stitch" d="M450 251C486 267 513 258 543 271" fill="none" stroke="#eeb098" stroke-width="2"/>
<!-- Long neck, white feathers, and the large throat pouch distinguish the pelican. -->
<path d="M514 283C541 270 529 240 540 215 547 195 548 181 557 168 567 156 590 157 602 172 615 189 613 206 601 222 584 241 574 253 575 280 577 319 550 346 526 362 502 381 459 376 437 356L409 351 427 336 403 317Q428 322 438 309C456 284 483 276 514 283Z" fill="url(#feather)" stroke="#7e8c75" stroke-width="2.6"/>
<path d="M442 346Q472 371 514 354C552 337 561 311 558 280 554 255 565 237 583 221" fill="none" stroke="#d9e0c9" stroke-width="10"/>
<path d="m416 323 22 10m-17 14 21 3" stroke="#9ba48c" stroke-width="2.5"/>
<path d="M547 208Q536 237 546 250" fill="none" stroke="#fffef8" stroke-width="4"/>
<path d="M609 199Q658 202 764 217C742 238 692 269 651 259 625 253 617 235 609 222Z" fill="url(#pouch)" stroke="#be8e54" stroke-width="2"/>
<path d="M624 218Q637 249 669 250" fill="none" stroke="#f7d59d" stroke-width="3.5"/>
<path d="M605 183C653 188 717 197 765 210Q776 214 764 224L608 207Q604 197 605 183Z" fill="#efb85f" stroke="#ae834e" stroke-width="2.2"/>
<path d="m614 189 139 23" stroke="#f9d58b" stroke-width="3"/>
<path d="M610 207 764 220" fill="none" stroke="#c18b43" stroke-width="1.5"/>
<path d="M766 213q7 3-2 11" fill="none" stroke="#a87445" stroke-width="2.2"/>
<ellipse cx="606" cy="191" rx="1.8" ry="1.2" fill="#ab814e"/>
<circle cx="584" cy="209" r="9" fill="#e9b699" opacity=".4"/>
<g id="eye" transform="translate(589 189)">
<ellipse rx="5.5" ry="6.4" fill="#344b3e"/>
<circle cx="1.6" cy="-2.3" r="1.6" fill="#fffdf2"/>
</g>
<path d="M581 178q6-4 11 0" fill="none" stroke="#7b8a6d" stroke-width="1.7"/>
<path d="M551 164C544 156 541 154 536 153M553 159q-6-12-14-14" stroke="#7e8c75" stroke-width="2.3" fill="none"/>
<g transform="rotate(-7 572 157)">
<path d="M543 160C542 139 557 128 575 131 591 133 600 144 601 161Z" fill="#d98267" stroke="#a56854" stroke-width="2"/>
<path d="M569 132q-10 12-9 27" fill="none" stroke="#ecb095" stroke-width="2.3"/>
<path d="M541 158q28-3 61 1l-1 6h-58Z" fill="#f1c1a1" stroke="#a56854" stroke-width="1.6"/>
<path d="M576 161Q610 150 629 165C620 172 598 173 577 168Z" fill="#d98267" stroke="#a56854" stroke-width="2"/>
<path d="M600 162q14-2 22 3" fill="none" stroke="#edae91" stroke-width="1.5"/>
</g>
<path d="M541 262Q555 273 577 270L575 283Q553 288 537 275Z" fill="#dc886c" stroke="#b5745c" stroke-width="1.5"/>
<path d="M544 265q11 9 29 8" fill="none" stroke="#efb49a" stroke-width="2"/>
<path d="M536 269q6-8 13-1l-1 9q-8 4-12-1Z" fill="#c6745e"/>
<!-- The long, folded wing rests on the handlebars. -->
<path d="M451 310C472 286 501 301 530 320 558 339 604 340 670 319Q684 315 689 326L682 335C642 350 606 357 575 354 542 361 510 357 485 347 466 340 453 330 451 310Z" fill="#e6e8d7" stroke="#7e8c75" stroke-width="2.4"/>
<path d="M466 312Q483 305 512 326T590 345" fill="none" stroke="#f9f8e9" stroke-width="5"/>
<path d="M607 337Q640 330 670 319 685 315 689 326L682 335Q653 346 625 350Z" fill="#7c8d7e"/>
<path d="M491 334q36 20 81 15m-54-7q36 16 73 8m43-13 37-12m-25 15 30-9" fill="none" stroke="#9aa68e" stroke-width="2"/>
</g>
<g id="bicycle-bell">
<path d="M680 315h15" stroke="#6a7555" stroke-width="3"/>
<path d="M680 313a7 7 0 0 1 14 0Z" fill="#e9bb66" stroke="#958053" stroke-width="1.8"/>
<path d="m693 310 5-3" stroke="#958053" stroke-width="2"/>
</g>
<g id="bell-rings" opacity="0" fill="none" stroke="#bca061" stroke-width="2.3">
<path d="M699 297q9 5 8 15M707 289q16 8 15 26M682 293q-9 5-9 14"/>
</g>
<g id="bell-word" opacity="0" transform="translate(742 307)">
<path d="M-18-27h57q12 0 12 12v11q0 12-12 12H3L-12 20l3-12h-9q-12 0-12-12v-11q0-12 12-12Z" fill="#fffdf2" stroke="#dbd9bd" stroke-width="1.5"/>
<text x="10" y="-3" text-anchor="middle" fill="#958052" font-size="15" font-family="PingFang SC, Microsoft YaHei, sans-serif">叮铃 ♪</text>
</g>
</g>
<g id="wind" fill="none" stroke="#fffdf0" stroke-width="2.5" stroke-linecap="round" opacity=".7">
<path id="wind-a" d="M281 270h37m-24 10h-28"/>
<path id="wind-b" d="M807 361h41m-14 9h29"/>
</g>
<g id="foreground">
<use href="#grass" transform="translate(116 641) scale(1.4)"/>
<use href="#grass" transform="translate(1035 664) scale(1.8)"/>
<use href="#grass" transform="translate(714 674) scale(.9)"/>
<use href="#grass" transform="translate(1516 641) scale(1.4)"/>
<use href="#grass" transform="translate(2435 664) scale(1.8)"/>
<use href="#grass" transform="translate(2114 674) scale(.9)"/>
</g>
<rect width="1200" height="650" fill="url(#paper-grain)" pointer-events="none"/>
<g transform="translate(42 47)" fill="#6f8878">
<path d="M0 0h27" stroke="currentColor" stroke-width="1" opacity=".5"/>
<text x="0" y="23" font-size="9" letter-spacing="2.5" font-family="sans-serif">THE COASTAL RIDE</text>
</g>
<text x="1157" y="613" text-anchor="end" fill="#91967d" font-family="sans-serif" font-size="9" letter-spacing="2">TAKE THE SCENIC ROUTE</text>
</svg>
<div class="controls">
<button class="play-button" id="play-pause" type="button" aria-label="暂停动画" aria-pressed="false">
<svg class="icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path id="play-icon" d="M5 4h3v12H5zm7 0h3v12h-3z"/></svg>
<span id="play-label">暂停</span>
</button>
<div class="speed-control">
<label for="speed">骑行速度</label>
<input type="range" id="speed" min="0.5" max="2" value="1" step="0.1" aria-valuetext="1 倍速">
<output id="speed-value" for="speed">1.0×</output>
</div>
<div class="control-end">
<span class="riding-status"><span class="status-dot"></span><span id="status-text">快乐骑行中</span></span>
<button class="bell-button" id="ring-bell" type="button" aria-label="按车铃,播放铃声">
<svg class="icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 13a6 6 0 0 1 12 0M3 14h14M7 17h6M10 5V3m4 2 2-2"/></svg>
叮铃一下
</button>
</div>
</div>
</section>
<footer><span class="footer-caption">海风正好,慢一点也没关系。</span><span>ENJOY THE LITTLE THINGS.</span></footer>
<span class="sr-only" id="announcement" role="status" aria-live="polite"></span>
</main>
<script>
(() => {
'use strict';
const byId = (id) => document.getElementById(id);
const elements = Object.fromEntries([
'ride', 'pelican-body', 'rear-wheel', 'front-wheel', 'cycle-shadow',
'back-leg-outline', 'back-leg-fill', 'front-leg-outline', 'front-leg-fill',
'back-crank', 'front-crank', 'front-crank-shine', 'back-foot', 'front-foot',
'flowers', 'eye', 'scarf-tail', 'scarf-stitch', 'hills', 'waves', 'road',
'dune-grass', 'foreground', 'cloud-a', 'cloud-b', 'cloud-c',
'distant-birds', 'sky-bird-a', 'sky-bird-b', 'sky-bird-c',
'wind-a', 'wind-b', 'bell-rings', 'bell-word', 'bicycle-bell',
'play-pause', 'play-icon', 'play-label', 'speed', 'speed-value',
'status-text', 'ring-bell', 'announcement'
].map((id) => [id, byId(id)]));
const motionPreference = window.matchMedia('(prefers-reduced-motion: reduce)');
const TAU = Math.PI * 2;
const CRANK = { x: 565, y: 465, radius: 27 };
const WHEEL_RADIUS = 76;
const GEAR_RATIO = 1.55;
let paused = motionPreference.matches;
let speed = 1;
let time = 0;
let lastTimestamp = null;
let frame = null;
let bellStart = -Infinity;
let audioContext;
const setTransform = (id, value) => elements[id].setAttribute('transform', value);
const setPath = (id, value) => elements[id].setAttribute('d', value);
// Two-segment inverse kinematics keep the ankles on the moving pedals.
function drawLeg(side, angle, bodyBob) {
const front = side === 'front';
const hipX = front ? 518 : 500;
const hipY = (front ? 360 : 358) + bodyBob;
const pedalX = CRANK.x + Math.cos(angle) * CRANK.radius;
const pedalY = CRANK.y + Math.sin(angle) * CRANK.radius - 5;
const ankleX = pedalX - 7;
const ankleY = pedalY - 9;
const dx = ankleX - hipX;
const dy = ankleY - hipY;
const distance = Math.hypot(dx, dy);
const upperLength = 76;
const lowerLength = 78;
const along = (upperLength ** 2 - lowerLength ** 2 + distance ** 2) / (2 * distance);
const outward = Math.sqrt(Math.max(0, upperLength ** 2 - along ** 2));
const kneeX = hipX + dx / distance * along + dy / distance * outward;
const kneeY = hipY + dy / distance * along - dx / distance * outward;
const leg = `M${hipX} ${hipY}L${kneeX} ${kneeY}L${ankleX} ${ankleY}`;
setPath(`${side}-leg-outline`, leg);
setPath(`${side}-leg-fill`, leg);
const crank = `M${CRANK.x} ${CRANK.y}L${pedalX} ${pedalY + 5}`;
setPath(`${side}-crank`, crank);
if (front) setPath('front-crank-shine', crank);
setTransform(`${side}-foot`, `translate(${pedalX} ${pedalY})`);
}
function drawScene() {
const angle = time * 2.7;
const distance = angle * GEAR_RATIO * WHEEL_RADIUS;
const bodyBob = Math.sin(angle * 2) * 1.8;
const bicycleBob = Math.sin(angle * 2 + .5) * .7;
const wheelDegrees = (angle * GEAR_RATIO * 180 / Math.PI) % 360;
setTransform('ride', `translate(0 ${bicycleBob})`);
setTransform('pelican-body', `translate(0 ${bodyBob})`);
setTransform('rear-wheel', `rotate(${wheelDegrees})`);
setTransform('front-wheel', `rotate(${wheelDegrees})`);
drawLeg('back', angle + Math.PI, bodyBob);
drawLeg('front', angle, bodyBob);
elements['cycle-shadow'].setAttribute('rx', 226 + Math.sin(angle * 2) * 2);
setTransform('flowers', `rotate(${Math.sin(time * 4.5) * 3 - 3} 405 365)`);
const flutter = Math.sin(time * 7) * 5;
const tail = Math.sin(time * 7 - 1.3) * 7;
setPath('scarf-tail', `M550 262C523 ${260 + flutter} 511 ${243 + flutter} 485 ${248 + tail}L445 ${244 + tail} 457 ${257 + tail} 442 ${267 + tail}C483 ${259 + tail} 513 ${287 + flutter} 551 277Z`);
setPath('scarf-stitch', `M450 ${251 + tail}C486 ${267 + tail} 513 ${258 + flutter} 543 271`);
const blinkPhase = time % 5.4;
const blink = blinkPhase > 4.98 && blinkPhase < 5.18
? Math.max(.09, Math.abs(blinkPhase - 5.08) / .1) : 1;
setTransform('eye', `translate(589 189) scale(1 ${blink})`);
setTransform('hills', `translate(${-((distance * .055) % 1200)} 0)`);
setTransform('waves', `translate(${-((distance * .12) % 600)} 0)`);
setTransform('dune-grass', `translate(${-((distance * .38) % 1400)} 0)`);
setTransform('road', `translate(${-(distance % 666)} 0)`);
setTransform('foreground', `translate(${-((distance * 1.2) % 1400)} 0)`);
[['cloud-a', 122, 5], ['cloud-b', 745, 3.2], ['cloud-c', 1046, 4]].forEach(([id, origin, pace]) => {
const x = ((origin + 240 - time * pace) % 1560 + 1560) % 1560 - 240;
setTransform(id, `translate(${x - origin} 0)`);
});
setTransform('distant-birds', `translate(${Math.sin(time * .22) * 24} ${Math.sin(time * .8) * 4})`);
const flap = Math.sin(time * 3) * 4;
setPath('sky-bird-a', `M339 169q9 ${-9 + flap} 18 0 9 ${-9 + flap} 18 0`);
setPath('sky-bird-b', `M300 189q6 ${-6 - flap * .7} 12 0 6 ${-6 - flap * .7} 12 0`);
setPath('sky-bird-c', `M1044 185q7 ${-7 + flap * .8} 14 0 7 ${-7 + flap * .8} 14 0`);
setTransform('wind-a', `translate(${-((time * 48) % 65)} 0)`);
setTransform('wind-b', `translate(${-((time * 54) % 76)} 0)`);
elements['wind-a'].setAttribute('opacity', .2 + .6 * Math.sin(time * 2) ** 2);
elements['wind-b'].setAttribute('opacity', .2 + .6 * Math.cos(time * 2 + .7) ** 2);
}
function drawBell(now) {
const elapsed = (now - bellStart) / 1000;
const active = elapsed < 1.35;
const fade = active ? Math.min(1, elapsed * 12) * Math.min(1, (1.35 - elapsed) * 3) : 0;
elements['bell-rings'].setAttribute('opacity', fade);
elements['bell-word'].setAttribute('opacity', fade);
const sway = active && !motionPreference.matches ? Math.sin(elapsed * 45) * 8 * Math.exp(-elapsed * 4) : 0;
setTransform('bicycle-bell', `rotate(${sway} 687 315)`);
setTransform('bell-word', `translate(742 ${307 - (motionPreference.matches ? 0 : Math.min(elapsed, 1.35) * 9)})`);
return active;
}
function tick(now) {
frame = null;
const delta = lastTimestamp === null ? 0 : Math.min((now - lastTimestamp) / 1000, .05);
lastTimestamp = now;
if (!paused) {
time += delta * speed;
drawScene();
}
const ringing = drawBell(now);
if ((!paused || ringing) && !document.hidden) frame = requestAnimationFrame(tick);
else lastTimestamp = null;
}
function wake() {
if (frame === null && !document.hidden) {
lastTimestamp = null;
frame = requestAnimationFrame(tick);
}
}
function updatePlayState() {
document.body.dataset.paused = String(paused);
elements['play-label'].textContent = paused ? '继续' : '暂停';
elements['play-pause'].setAttribute('aria-label', paused ? '继续动画' : '暂停动画');
elements['play-pause'].setAttribute('aria-pressed', String(paused));
elements['status-text'].textContent = paused ? '休息一下' : '快乐骑行中';
setPath('play-icon', paused ? 'M6 3.5 16 10 6 16.5Z' : 'M5 4h3v12H5zm7 0h3v12h-3z');
wake();
}
elements['play-pause'].addEventListener('click', () => {
paused = !paused;
updatePlayState();
});
elements.speed.addEventListener('input', (event) => {
speed = Number(event.target.value);
elements['speed-value'].textContent = `${speed.toFixed(1)}×`;
elements.speed.setAttribute('aria-valuetext', `${speed.toFixed(1)} 倍速`);
});
// Audio is generated locally, and starts only after pressing the bell.
async function playBell() {
try {
const AudioContextClass = window.AudioContext || window.webkitAudioContext;
if (!AudioContextClass) return;
audioContext ||= new AudioContextClass();
if (audioContext.state === 'suspended') await audioContext.resume();
const start = audioContext.currentTime;
[0, .16].forEach((delay) => {
[1568, 3136, 4234].forEach((frequency, index) => {
const oscillator = audioContext.createOscillator();
const gain = audioContext.createGain();
oscillator.type = 'sine';
oscillator.frequency.value = frequency;
gain.gain.setValueAtTime(.0001, start + delay);
gain.gain.exponentialRampToValueAtTime(.065 / (index + 1), start + delay + .006);
gain.gain.exponentialRampToValueAtTime(.0001, start + delay + .9);
oscillator.connect(gain);
gain.connect(audioContext.destination);
oscillator.start(start + delay);
oscillator.stop(start + delay + 1);
oscillator.addEventListener('ended', () => { oscillator.disconnect(); gain.disconnect(); });
});
});
} catch {
// The visual bell remains available when audio is unavailable.
}
}
elements['ring-bell'].addEventListener('click', () => {
bellStart = performance.now();
elements.announcement.textContent = '叮铃!鹈鹕按响了车铃。';
playBell();
wake();
});
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
if (frame !== null) cancelAnimationFrame(frame);
frame = null;
lastTimestamp = null;
} else wake();
});
motionPreference.addEventListener('change', (event) => {
if (event.matches) {
paused = true;
updatePlayState();
}
});
drawScene();
updatePlayState();
})();
</script>
</body>
</html>
最新回复 (3)
-
Miaosful 09-07 09:361楼我感觉也没啥进步空间了,建议佬友们开发难度更大的 svg 测试 ^-^
-
fanxu 09-07 09:372楼
整
这个看起来好完整,看起来很舒服欸
-
Aiden Q 09-07 16:103楼
感觉都一样啊,ultra,sub2出来的
* 帖子来源Linux.do
附近帖子
- ↑要不要从 glm pro 换 gpt 5x
- ↑参加穿叉叉裤长大的发小婚礼,佬们有没有什么礼物推荐
- ↑雷达对 Astra 的最新智商监测 终于出炉了,快来看看吧
- ↑codex看不到gpt6,有没有大佬知道啥情况的?已解决感觉各位佬,修改了配置文件
- ↑这么看Astra是不是可以取代sol和terra了?
- 📍 astra max 鹈鹕测试 不降智
- ↓GPT 6 astra 疑似有较为严重的中文语料库污染(编辑:应该是低级模型的问题。。。。
- ↓特朗普分享了将新墨西哥修改为新美国的图片
- ↓从香港机场转机能办理什么香港银行卡吗?【结贴,一个也办不了】
- ↓买su7的心蠢蠢欲动,求佬们骂醒我
- ↓现在openai 已经开始风控了,打击中转直接降智,个人用户也受影响
飞读
qianye
|
主题数 1 |
帖子数 1 |
注册排名 3 |