• Marisa

    DSH:

    图片```
    1 轮 · 7 步| LLM 15m22s · 工具调用 0.2s| 首 token 平均 1s · 72 tok/s| 缓存命中 97%| 输入 446K tok · 输出 66.1K tok
    ```效果:

    图片


    代码:```
    <!doctype html>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Pelican Pedaler — No. 7</title>
    <link rel="preconnect" href="https://fonts.googleapis.com"&gt;
    <link rel="preconnect" href="https://fonts.gstatic.com&quot; crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Karla:wght@400;600&family=Space+Mono:wght@400;700&family=Staatliches&display=swap&quot; rel="stylesheet">
    <style>
    :root{
    --ink:#18323c;
    --sky:#bfe0e4;
    --sky-hi:#eaf4f1;
    --sea:#2e7185;
    --sea-hi:#4e93a4;
    --sand:#efe2c4;
    --ivory:#f8f4e6;
    --ivory-shade:#ebe2c8;
    --coral:#e9763d;
    --coral-deep:#d9612b;
    --sun:#f2c14e;
    }
    *{ box-sizing:border-box; }
    html,body{ margin:0; padding:0; }
    body{
    background:var(--ink);
    color:var(--ink);
    font-family:'Karla',system-ui,sans-serif;
    -webkit-font-smoothing:antialiased;
    text-rendering:optimizeLegibility;
    }

    .poster{ position:relative; min-height:100vh; min-height:100svh; overflow:hidden; background:var(--sky); }

    / ---- stage (the artwork) ---- /
    .stage{ position:absolute; inset:0; overflow:hidden; }
    #scene{ display:block; width:100%; height:100%; }

    .grain{
    position:absolute; inset:0; pointer-events:none; opacity:.05; mix-blend-mode:multiply;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg&#039; width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size:160px 160px;
    }
    .frame{
    position:absolute; inset:14px; border:1.5px solid rgba(24,50,60,.55); pointer-events:none;
    }

    / ---- overlay text ---- /
    .topbar{
    position:absolute; top:clamp(1.1rem,3vw,2.4rem); left:clamp(1.1rem,3vw,2.4rem); right:clamp(1.1rem,3vw,2.4rem);
    display:flex; justify-content:space-between; gap:1rem; align-items:baseline; pointer-events:none;
    }
    .eyebrow{
    font-family:'Space Mono',monospace; font-size:12px; font-weight:700; letter-spacing:.22em;
    text-transform:uppercase; color:var(--ink); opacity:.85; margin:0;
    }
    .hint{
    font-family:'Space Mono',monospace; font-size:12px; letter-spacing:.16em;
    text-transform:uppercase; color:var(--ink); margin:0;
    }

    .content{
    position:absolute; inset:0; display:flex; flex-direction:column; justify-content:space-between;
    padding:clamp(1.1rem,3vw,2.4rem); padding-top:clamp(6rem,12vw,9rem); pointer-events:none;
    }
    .titleblock{ max-width:15ch; }
    .title{
    font-family:'Staatliches',Impact,'Arial Narrow',sans-serif; font-weight:400;
    font-size:clamp(3.4rem,11vw,8rem); line-height:.84; letter-spacing:.01em;
    text-transform:uppercase; color:var(--ink); margin:0;
    }
    .title .dot{ color:var(--coral); }
    .sub{
    font-size:clamp(1rem,1.5vw,1.2rem); line-height:1.55; max-width:38ch;
    color:var(--ink); margin:1.1rem 0 0;
    }

    .specbar{
    pointer-events:auto; display:flex; align-items:center; justify-content:space-between; gap:1rem; flex-wrap:wrap;
    background:rgba(248,244,230,.92); border:1.5px solid var(--ink); padding:.7rem 1rem;
    backdrop-filter:blur(2px);
    }
    .specs{
    display:flex; gap:1.1rem; flex-wrap:wrap; margin:0;
    font-family:'Space Mono',monospace; font-size:12px; letter-spacing:.14em; text-transform:uppercase; color:var(--ink);
    }
    .specs b{ font-weight:700; }
    .specs span{ opacity:.6; }
    .controls{ display:flex; align-items:center; gap:.6rem; flex-wrap:wrap; }
    .distance{ font-family:'Space Mono',monospace; font-size:13px; font-weight:700; letter-spacing:.06em; color:var(--ink); white-space:nowrap; }
    .distance small{ font-weight:400; opacity:.65; }
    button.ctl{
    font-family:'Space Mono',monospace; font-size:12px; font-weight:700; letter-spacing:.12em; text-transform:uppercase;
    color:var(--ink); background:transparent; border:1.5px solid var(--ink); padding:.55rem .8rem; cursor:pointer;
    transition:background .15s ease, color .15s ease, border-color .15s ease;
    }
    button.ctl:hover{ background:var(--coral); color:var(--ivory); border-color:var(--coral); }
    button.ctl:focus-visible{ outline:3px solid var(--coral); outline-offset:2px; }

    / ---- SVG styling ---- /
    .tire{ fill:none; stroke:var(--ink); stroke-width:12; }
    .rim{ fill:none; stroke:var(--ink); stroke-width:3; opacity:.7; }
    .hub{ fill:var(--ink); }
    .frame-line{ stroke:var(--coral); stroke-width:10; stroke-linecap:round; }
    .bar{ fill:none; stroke:var(--coral); stroke-width:9; stroke-linecap:round; stroke-linejoin:round; }
    .chainring{ fill:none; stroke:var(--ink); stroke-width:6; }
    .chainring-dot{ fill:var(--ink); }
    .chain{ stroke:var(--ink); stroke-width:4; stroke-dasharray:5 5; opacity:.28; fill:none; }
    .cog{ fill:none; stroke:var(--ink); stroke-width:4; }
    .saddle{ fill:var(--ink); }
    .crank{ stroke:var(--ink); stroke-width:6; stroke-linecap:round; }
    .pedal{ fill:var(--ink); }

    .p-body{ fill:var(--ivory); }
    .p-shade{ fill:var(--ivory-shade); }
    .p-bill{ fill:var(--coral); }
    .p-pouch{ fill:var(--coral-deep); }
    .p-eye{ fill:var(--ink); }
    .p-fish{ fill:var(--sea-hi); }
    .leg{ fill:none; stroke:var(--coral); stroke-width:9; stroke-linecap:round; stroke-linejoin:round; }
    .leg.far{ stroke:var(--coral-deep); }
    .foot{ fill:var(--coral); }
    .foot.far{ fill:var(--coral-deep); }
    .feather{ stroke:var(--ink); stroke-width:2; opacity:.3; fill:none; stroke-linecap:round; }

    .callout .pill{ fill:rgba(248,244,230,.93); stroke:var(--ink); stroke-width:1.5; }
    .callout .clabel{ font-family:'Space Mono',monospace; font-size:12px; font-weight:700; letter-spacing:1px; fill:var(--ink); text-transform:uppercase; }
    .callout .csub{ font-family:'Space Mono',monospace; font-size:11px; letter-spacing:.4px; fill:var(--ink); opacity:.72; }
    .callout .leader{ stroke:var(--ink); stroke-width:1.5; stroke-dasharray:4 4; fill:none; }
    .callout .dot{ fill:var(--coral); stroke:var(--ink); stroke-width:1.5; }
    .callout{ opacity:0; animation:rise .7s ease forwards; }
    @keyframes rise{ from{ opacity:0; transform:translateY(10px); } to{ opacity:1; transform:translateY(0); } }

    .bubble-text{ font-family:'Staatliches',Impact,sans-serif; font-size:28px; letter-spacing:.08em; fill:var(--ink); }
    #bubble{ opacity:0; pointer-events:none; transform-box:fill-box; transform-origin:50% 100%; }
    #upper-bill{ transform-box:fill-box; transform-origin:0% 50%; transition:transform .14s cubic-bezier(.34,1.56,.64,1); }
    .poster.honking #upper-bill{ transform:rotate(-14deg); }
    .poster.honking #bubble{ animation:honk-pop .52s ease; }
    @keyframes honk-pop{ 0%{ opacity:0; transform:scale(.4);} 25%{ opacity:1; transform:scale(1.12);} 60%{ opacity:1; transform:scale(1);} 100%{ opacity:0; transform:scale(1);} }

    / ambient motion /
    .cloud{ animation:drift 26s ease-in-out infinite; }
    .cloud.c2{ animation-duration:34s; animation-delay:-8s; }
    .cloud.c3{ animation-duration:42s; animation-delay:-16s; }
    @keyframes drift{ 0%,100%{ transform:translateX(0);} 50%{ transform:translateX(-70px);} }

    .sun-rays{ transform-box:view-box; transform-origin:1050px 140px; animation:spin 70s linear infinite; }
    @keyframes spin{ to{ transform:rotate(360deg);} }

    .foam{ stroke:var(--ivory); stroke-width:5; stroke-linecap:round; stroke-dasharray:22 26; opacity:.92; animation:m1 1.4s linear infinite; }
    .glint{ stroke:var(--sky-hi); stroke-width:4; stroke-linecap:round; stroke-dasharray:40 60; opacity:.6; animation:m2 3.4s linear infinite; }
    .sandline{ stroke:#d9c79a; stroke-width:9; stroke-linecap:round; stroke-dasharray:70 90; opacity:.55; animation:m3 2.6s linear infinite; }
    @keyframes m1{ to{ stroke-dashoffset:-48; } }
    @keyframes m2{ to{ stroke-dashoffset:-100; } }
    @keyframes m3{ to{ stroke-dashoffset:-160; } }

    .speedlines{ animation:pulse 1.2s ease-in-out infinite; }
    @keyframes pulse{ 0%,100%{ opacity:.12; } 50%{ opacity:.28; } }

    / ---- responsive ---- /
    @media (max-width: 860px){
    .poster{ min-height:0; display:flex; flex-direction:column; }
    .stage{ position:relative; inset:auto; height:58svh; min-height:320px; flex:none; }
    .frame{ display:none; }
    .callout{ display:none; }
    .topbar{ position:static; padding:1.1rem 1.1rem 0; order:-1; }
    .content{ position:static; padding:1.4rem 1.1rem 2rem; gap:1.5rem; justify-content:flex-start; }
    .titleblock{ max-width:none; }
    .sub{ max-width:46ch; }
    }

    @media (prefers-reduced-motion: reduce){
    .cloud,.sun-rays,.foam,.glint,.sandline,.speedlines,.callout{ animation:none !important; }
    .callout{ opacity:1; }
    #upper-bill{ transition-duration:.01s; }
    .poster.honking #bubble{ animation-duration:.01s; }
    }
    </style>
    </head>
    <body>
    <div class="poster" id="poster">

    <div class="stage">
    <svg id="scene" viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid slice"
    role="img" aria-label="Animated illustration of a pelican riding a bicycle along the shore">
    <defs>
    <linearGradient id="skyGrad" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0" stop-color="#eaf4f1"/>
    <stop offset="0.7" stop-color="#cbe5e7"/>
    <stop offset="1" stop-color="#a7d3db"/>
    </linearGradient>
    <linearGradient id="seaGrad" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0" stop-color="#3b8294"/>
    <stop offset="1" stop-color="#236070"/>
    </linearGradient>
    <linearGradient id="sandGrad" x1="0" y1="0" x2="0" y2="1">
    <stop offset="0" stop-color="#f7eed8"/>
    <stop offset="1" stop-color="#efe2c4"/>
    </linearGradient>

    <g id="wheelDef">
    <circle r="62" class="tire"/>
    <circle r="51" class="rim"/>
    <g stroke="#18323c" stroke-width="2.4" opacity="0.55">
    <line x1="0" y1="0" x2="50" y2="0"/>
    <line x1="0" y1="0" x2="35.4" y2="35.4"/>
    <line x1="0" y1="0" x2="0" y2="50"/>
    <line x1="0" y1="0" x2="-35.4" y2="35.4"/>
    <line x1="0" y1="0" x2="-50" y2="0"/>
    <line x1="0" y1="0" x2="-35.4" y2="-35.4"/>
    <line x1="0" y1="0" x2="0" y2="-50"/>
    <line x1="0" y1="0" x2="35.4" y2="-35.4"/>
    </g>
    <circle r="9" class="hub"/>
    </g>

    <g id="cloud">
    <ellipse cx="0" cy="0" rx="46" ry="20" fill="#f8f4e6"/>
    <circle cx="-26" cy="6" r="18" fill="#f8f4e6"/>
    <circle cx="26" cy="6" r="18" fill="#f8f4e6"/>
    </g>
    </defs>

    <!-- sky -->
    <rect x="0" y="0" width="1200" height="700" fill="url(#skyGrad)"/>

    <!-- sun -->
    <g>
    <circle cx="1050" cy="140" r="62" fill="#f2c14e"/>
    <g class="sun-rays" stroke="#f2c14e" stroke-width="5" stroke-linecap="round">
    <line x1="1120" y1="140" x2="1142" y2="140"/>
    <line x1="1099.5" y1="90.5" x2="1115" y2="75"/>
    <line x1="1050" y1="70" x2="1050" y2="48"/>
    <line x1="1000.5" y1="90.5" x2="985" y2="75"/>
    <line x1="980" y1="140" x2="958" y2="140"/>
    <line x1="1000.5" y1="189.5" x2="985" y2="205"/>
    <line x1="1050" y1="210" x2="1050" y2="232"/>
    <line x1="1099.5" y1="189.5" x2="1115" y2="205"/>
    </g>
    </g>

    <!-- clouds -->
    <g class="cloud"><use href="#cloud" transform="translate(300 110) scale(0.8)"/></g>
    <g class="cloud c2"><use href="#cloud" transform="translate(880 80) scale(1.05)"/></g>
    <g class="cloud c3"><use href="#cloud" transform="translate(540 180) scale(0.6)"/></g>

    <!-- sea + sand -->
    <path d="M0 450 C 110 442 220 458 340 450 C 460 442 560 458 680 450 C 800 442 920 458 1040 450 C 1100 446 1150 452 1200 450 L 1200 560 L 0 560 Z" fill="url(#seaGrad)"/>
    <rect x="0" y="560" width="1200" height="140" fill="url(#sandGrad)"/>

    <!-- waterline foam, glints, ground motion, decorations, shadow -->
    <line x1="-40" y1="560" x2="1240" y2="560" class="foam"/>
    <line x1="60" y1="492" x2="140" y2="492" class="glint"/>
    <line x1="360" y1="514" x2="460" y2="514" class="glint"/>
    <line x1="820" y1="486" x2="900" y2="486" class="glint"/>
    <line x1="-40" y1="620" x2="1240" y2="620" class="sandline"/>

    <polygon points="140,626 143.5,635 153,636 146,642 148,651 140,646 132,651 134,642 127,636 136.5,635" fill="#e9763d" opacity="0.45"/>
    <path d="M1112 646 C 1108 636 1114 630 1124 630 C 1134 630 1140 636 1136 646 C 1130 642 1118 642 1112 646 Z" fill="#236070" opacity="0.45"/>

    <ellipse cx="640" cy="566" rx="190" ry="12" fill="#18323c" opacity="0.08"/>

    <!-- speed lines behind the rider -->
    <g class="speedlines" stroke="#18323c" stroke-linecap="round">
    <line x1="270" y1="352" x2="382" y2="352" stroke-width="6"/>
    <line x1="290" y1="382" x2="408" y2="382" stroke-width="5"/>
    <line x1="262" y1="412" x2="368" y2="412" stroke-width="4"/>
    </g>

    <!-- far leg (behind frame) -->
    <path id="leg-far" class="leg far" d="M 516 323 L 515.6 442.9 L 614 515"/>

    <!-- far crank + pedal + foot (behind frame) -->
    <g id="crank-far" transform="translate(640 515) rotate(180)">
    <line x1="0" y1="0" x2="26" y2="0" class="crank"/>
    </g>
    <g id="pedal-far" transform="translate(614 515)">
    <rect x="-13" y="-3" width="26" height="7" rx="3" class="pedal"/>
    <path class="foot far" d="M 0 0 C 6 -3 16 -3 24 1 C 28 4 27 8 22 10 C 17 8 15 7 13 9 C 11 13 7 15 3 13 C 1 10 3 8 2 6 C 1 3 0 2 0 0 Z"/>
    </g>

    <!-- wheels -->
    <g transform="translate(470 500)"><g id="spin-rear"><use href="#wheelDef"/></g></g>
    <g transform="translate(810 500)"><g id="spin-front"><use href="#wheelDef"/></g></g>

    <!-- frame -->
    <g>
    <line x1="640" y1="515" x2="545" y2="350" class="frame-line"/>
    <line x1="640" y1="515" x2="795" y2="372" class="frame-line"/>
    <line x1="545" y1="350" x2="820" y2="330" class="frame-line"/>
    <line x1="470" y1="500" x2="640" y2="515" class="frame-line"/>
    <line x1="470" y1="500" x2="545" y2="350" class="frame-line"/>
    <line x1="545" y1="350" x2="527" y2="322" class="frame-line"/>
    <line x1="810" y1="500" x2="795" y2="372" class="frame-line"/>
    <line x1="795" y1="372" x2="820" y2="330" class="frame-line"/>

    <!-- handlebar -->
    <line x1="820" y1="330" x2="850" y2="312" class="bar"/>
    <path d="M 850 312 C 874 304 886 316 878 336 C 872 348 858 350 850 342" class="bar"/>

    <!-- chainring + chain -->
    <circle cx="640" cy="515" r="30" class="chainring"/>
    <circle cx="640" cy="515" r="9" class="chainring-dot"/>
    <g class="chainring-dot">
    <circle cx="640" cy="496" r="3.4"/>
    <circle cx="640" cy="534" r="3.4"/>
    <circle cx="621" cy="515" r="3.4"/>
    <circle cx="659" cy="515" r="3.4"/>
    <circle cx="626.6" cy="501.6" r="3.4"/>
    <circle cx="653.4" cy="528.4" r="3.4"/>
    <circle cx="626.6" cy="528.4" r="3.4"/>
    <circle cx="653.4" cy="501.6" r="3.4"/>
    </g>
    <line x1="640" y1="485" x2="470" y2="488" class="chain"/>
    <line x1="640" y1="545" x2="470" y2="512" class="chain"/>
    <circle cx="470" cy="500" r="12" class="cog"/>

    <!-- saddle -->
    <path class="saddle" d="M 497 322 C 499 308 521 300 541 302 C 559 304 563 314 555 322 C 539 330 507 328 497 322 Z"/>
    </g>

    <!-- near leg (over frame) -->
    <path id="leg-near" class="leg" d="M 525 330 L 568.3 441.9 L 666 515"/>

    <!-- pelican body (bobs) -->
    <g id="pelican-body" transform="translate(0 0)">
    <!-- tail -->
    <path class="p-shade" d="M 500 316 C 486 300 472 302 458 292 C 472 302 468 308 476 312 C 460 310 464 320 478 324 C 490 330 496 326 500 316 Z"/>
    <!-- body -->
    <path class="p-body" d="M 498 340 C 490 306 512 294 548 294 C 584 294 606 310 610 340 C 614 366 578 380 548 380 C 518 380 502 366 498 340 Z"/>
    <!-- wing -->
    <path class="p-shade" d="M 520 314 C 528 330 552 340 578 342 C 596 344 604 336 604 328 C 582 336 548 332 526 322 C 520 318 518 316 520 314 Z"/>
    <path class="feather" d="M 528 322 C 546 332 566 337 588 335"/>
    <path class="feather" d="M 524 316 C 544 322 562 324 582 322"/>
    <!-- neck + head -->
    <path class="p-body" d="M 596 306 C 606 272 622 244 646 226 L 672 236 C 656 250 644 278 626 306 Z"/>
    <circle cx="655" cy="208" r="21" class="p-body"/>
    <circle cx="663" cy="200" r="4" class="p-eye"/>
    <circle cx="664" cy="199" r="1.4" fill="#ffffff"/>
    <!-- bill -->
    <path id="upper-bill" class="p-bill" d="M 673 200 C 712 194 750 206 790 220 C 793 223 790 227 783 225 C 748 221 706 212 678 207 C 674 205 673 202 673 200 Z"/>
    <path class="p-pouch" d="M 676 207 C 690 248 722 272 758 262 C 764 250 758 230 744 222 C 718 213 694 210 676 207 Z"/>
    <!-- cargo fish -->
    <g class="p-fish" transform="translate(726 240) rotate(-14)">
    <ellipse cx="0" cy="0" rx="12" ry="6"/>
    <path d="M 10 0 L 20 -6 L 18 6 Z"/>
    <circle cx="-4" cy="-1.5" r="1.4" fill="#18323c"/>
    </g>
    </g>

    <!-- near crank + pedal + foot -->
    <g id="crank-near" transform="translate(640 515) rotate(0)">
    <line x1="0" y1="0" x2="26" y2="0" class="crank"/>
    </g>
    <g id="pedal-near" transform="translate(666 515)">
    <rect x="-13" y="-3" width="26" height="7" rx="3" class="pedal"/>
    <path class="foot" d="M 0 0 C 6 -3 16 -3 24 1 C 28 4 27 8 22 10 C 17 8 15 7 13 9 C 11 13 7 15 3 13 C 1 10 3 8 2 6 C 1 3 0 2 0 0 Z"/>
    </g>

    <!-- spec callouts -->
    <g class="callout" style="animation-delay:.2s">
    <line class="leader" x1="736" y1="148" x2="782" y2="222"/>
    <circle class="dot" cx="782" cy="222" r="4"/>
    <g transform="translate(710 126)">
    <rect class="pill" x="-105" y="-23" width="210" height="46" rx="13"/>
    <text class="clabel" x="0" y="-5" text-anchor="middle">Aero Bill</text>
    <text class="csub" x="0" y="11" text-anchor="middle">rated 40 km/h · bone dry</text>
    </g>
    </g>

    <g class="callout" style="animation-delay:.4s">
    <line class="leader" x1="706" y1="370" x2="670" y2="262"/>
    <circle class="dot" cx="670" cy="262" r="4"/>
    <g transform="translate(770 392)">
    <rect class="pill" x="-105" y="-23" width="210" height="46" rx="13"/>
    <text class="clabel" x="0" y="-5" text-anchor="middle">Cargo Pouch</text>
    <text class="csub" x="0" y="11" text-anchor="middle">1 fish · live · secured</text>
    </g>
    </g>

    <g class="callout" style="animation-delay:.6s">
    <line class="leader" x1="566" y1="584" x2="640" y2="515"/>
    <circle class="dot" cx="640" cy="515" r="4"/>
    <g transform="translate(498 600)">
    <rect class="pill" x="-105" y="-23" width="210" height="46" rx="13"/>
    <text class="clabel" x="0" y="-5" text-anchor="middle">Single Speed</text>
    <text class="csub" x="0" y="11" text-anchor="middle">no gears, ever</text>
    </g>
    </g>

    <!-- honk bubble -->
    <g id="bubble" transform="translate(645 96)">
    <rect x="-52" y="-34" width="104" height="42" rx="13" fill="#f8f4e6" stroke="#18323c" stroke-width="2.5"/>
    <path d="M -8 8 L 0 28 L 12 8 Z" fill="#f8f4e6" stroke="#18323c" stroke-width="2.5" stroke-linejoin="round"/>
    <text x="0" y="-7" text-anchor="middle" class="bubble-text">HONK!</text>
    </g>
    </svg>
    </div>

    <header class="topbar">
    <p class="eyebrow">Société Vélocipédique du Littoral · Poster No. 7</p>
    <p class="hint">Click the pelican &#10230;</p>
    </header>

    <main class="content">
    <div class="titleblock">
    <h1 class="title">Pelican<br>Pedaler<span class="dot">.</span></h1>
    <p class="sub">A single-speed study in applied optimism. Fourteen kilos of bicycle, three of bird, and one very committed beak — riding the waterline since 1904.</p>
    </div>

    <footer class="specbar">
    <p class="specs">
    <b>1</b><span>gear</span>
    <b>40</b><span>cm rims</span>
    <b>1</b><span>fish · live</span>
    <b>2.4</b><span>m wingspan</span>
    <b>est.</b><span>1904</span>
    </p>
    <div class="controls">
    <span class="distance"><span id="distance-num">0.00</span> <small>km</small></span>
    <button class="ctl" id="toggle" aria-pressed="false">Hold on</button>
    <button class="ctl" id="speed" aria-pressed="false">Pace · Cruise</button>
    </div>
    </footer>
    </main>

    <div class="grain"></div>
    <div class="frame"></div>
    </div>

    <script>
    (function () {
    var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    var poster = document.getElementById('poster');
    var body = document.getElementById('pelican-body');
    var legN = document.getElementById('leg-near');
    var legF = document.getElementById('leg-far');
    var crankN = document.getElementById('crank-near');
    var crankF = document.getElementById('crank-far');
    var pedalN = document.getElementById('pedal-near');
    var pedalF = document.getElementById('pedal-far');
    var spinR = document.getElementById('spin-rear');
    var spinF = document.getElementById('spin-front');
    var distEl = document.getElementById('distance-num');
    var toggleBtn = document.getElementById('toggle');
    var speedBtn = document.getElementById('speed');

    var BB = { x: 640, y: 515 };
    var R = 26;
    var HIPN = { x: 525, y: 330 };
    var HIPF = { x: 516, y: 323 };
    var L1 = 120, L2 = 122;
    var WHEEL_RATIO = 1.6;
    var MPR = 3.4; // metres per crank revolution (cartoon physics)

    var running = true;
    var sprint = false;
    var rps = 1.25, target = 1.25;
    var angle = 0, wheelAngle = 0, distance = 0;

    function knee(H, P) {
    var dx = P.x - H.x, dy = P.y - H.y;
    var d = Math.hypot(dx, dy);
    d = Math.min(Math.max(d, Math.abs(L1 - L2) + 0.01), L1 + L2 - 0.01);
    var a = (L1 L1 - L2 L2 + d d) / (2 d);
    var h = Math.sqrt(Math.max(0, L1 L1 - a a));
    var ux = dx / d, uy = dy / d;
    var mx = H.x + ux a, my = H.y + uy a;
    var px = -uy h, py = ux h;
    var k1 = { x: mx + px, y: my + py };
    var k2 = { x: mx - px, y: my - py };
    return (k1.x <= k2.x) ? k1 : k2; // bird knee bends backward
    }

    function legD(H, P) {
    var K = knee(H, P);
    return 'M ' + H.x + ' ' + H.y +
    ' L ' + K.x.toFixed(1) + ' ' + K.y.toFixed(1) +
    ' L ' + P.x.toFixed(1) + ' ' + P.y.toFixed(1);
    }

    function deg(a) { return (a * 180 / Math.PI) % 360; }

    function update(theta, bx, by) {
    var Pn = { x: BB.x + R Math.cos(theta), y: BB.y + R Math.sin(theta) };
    var Pf = { x: BB.x - R Math.cos(theta), y: BB.y - R Math.sin(theta) };
    var Hn = { x: HIPN.x + bx, y: HIPN.y + by };
    var Hf = { x: HIPF.x + bx * 0.85, y: HIPF.y + by };

    legN.setAttribute('d', legD(Hn, Pn));
    legF.setAttribute('d', legD(Hf, Pf));
    crankN.setAttribute('transform', 'translate(' + BB.x + ' ' + BB.y + ') rotate(' + deg(theta) + ')');
    crankF.setAttribute('transform', 'translate(' + BB.x + ' ' + BB.y + ') rotate(' + deg(theta + Math.PI) + ')');
    pedalN.setAttribute('transform', 'translate(' + Pn.x.toFixed(2) + ' ' + Pn.y.toFixed(2) + ')');
    pedalF.setAttribute('transform', 'translate(' + Pf.x.toFixed(2) + ' ' + Pf.y.toFixed(2) + ')');

    var w = deg(wheelAngle);
    spinR.setAttribute('transform', 'rotate(' + w + ')');
    spinF.setAttribute('transform', 'rotate(' + w + ')');
    body.setAttribute('transform', 'translate(' + bx.toFixed(2) + ' ' + by.toFixed(2) + ')');
    }

    var last = performance.now();
    function frame(now) {
    var dt = Math.min((now - last) / 1000, 0.05);
    last = now;
    rps += (target - rps) Math.min(1, dt 5);
    if (running) {
    var dTheta = rps Math.PI 2 * dt;
    angle += dTheta;
    wheelAngle += dTheta * WHEEL_RATIO;
    distance += rps MPR dt / 1000;
    distEl.textContent = distance.toFixed(2);
    }
    var by = Math.sin(angle 2) 2.4;
    var bx = Math.cos(angle 2) 0.7;
    update(angle, bx, by);
    requestAnimationFrame(frame);
    }

    toggleBtn.addEventListener('click', function () {
    running = !running;
    toggleBtn.textContent = running ? 'Hold on' : 'Ride on';
    toggleBtn.setAttribute('aria-pressed', String(!running));
    });

    speedBtn.addEventListener('click', function () {
    sprint = !sprint;
    target = sprint ? 2.3 : 1.25;
    speedBtn.textContent = sprint ? 'Pace · Sprint' : 'Pace · Cruise';
    speedBtn.setAttribute('aria-pressed', String(sprint));
    });

    var honkT;
    body.style.cursor = 'pointer';
    body.addEventListener('click', function () {
    if (honkT) clearTimeout(honkT);
    poster.classList.remove('honking');
    void poster.offsetWidth; // restart animation
    poster.classList.add('honking');
    honkT = setTimeout(function () { poster.classList.remove('honking'); }, 540);
    });

    if (reduced) {
    update(0, 0, 0);
    } else {
    requestAnimationFrame(frame);
    }
    })();
    </script>
    </body>
    </html>

    主楼
  • sandiferresner

    为什么不开 max 测, 估计效果会更好.

    #1
  • Marisa

    图片

    Max生成的 根本动不了

    #2

发表回复

登录后回复