枠の中でスクロール・クリックして動きを試せます。端末指定は実寸表示です。幅が足りない場合は横にスクロールできます。
再現プロンプト
架空の精密オーディオ工房「VERNIER」の1ページサイト。中央の物理ダイヤルはドラッグ/ホイールで回転し、指数減衰の慣性で惰性回転したのち3°刻みの目盛りにカチッとスナップする。周波数風LCD・針と目盛りの計器言語・回転角に連動する背景色相という同じ語彙を、プリセット一覧のミニダイヤル、製品スペックの半円ゲージ(ウォルナット×アルミの透過製品カット付き)、スクロール連動の周波数スケール、フッターの常時回転ダイヤルまで一貫して使い回す。 配色・構成・動きの数値をまとめた指示書です。 お使いのAIに貼り、素材やお店の情報を伝えて実装してください。仕上がりは利用するAIと素材によって変わります。
Build a single self-contained HTML file (inline CSS/JS; you may load GSAP + ScrollTrigger from a CDN — `https://unpkg.com/gsap@3/dist/gsap.min.js`, `https://unpkg.com/gsap@3/dist/ScrollTrigger.min.js` — no other runtime dependencies, no external images or fetch calls) for "VERNIER" — a fictional precision-audio workshop ("Precision Tuning Co. — est. 2019"). The entire page's motion language is "the dial is the interface": one physical-feeling rotary knob in the hero drives inertia-and-snap rotation, and the exact same tick/needle/scale grammar re-appears in every section below it. The page scrolls normally with the window (the inner-scroll-container constraint described below is specific to the MOTION PALETTE embed and not needed standalone — build one long document-flow page and drive every ScrollTrigger off the default window scroller).
## Art direction
Background `#141110` (near-black warm brown), card surface `#1D1917` (hover `#252019`), hairline border `rgba(243,236,221,0.09)`, foreground `#F3ECDD` (warm cream), muted `#9C8F80`, and a fixed brand accent `#E0533D` used for the CTA, every needle, the LCD digits and the active preset dot — this accent is never overridden by the hue drift described in Signature 4. Headings use a bold condensed uppercase sans (Oswald-style, weight 600–700); body copy uses a clean grotesque (Inter, 400–600); every numeric or technical readout — the LCD frequency, tick labels, eyebrows, log dates — uses a monospace face (JetBrains Mono). Section padding is `clamp(3rem,8vh,6rem) clamp(1.25rem,5vw,3rem)` with a 1px hairline top-border between sections. Never use a marquee, a magnetic button, a scroll-triggered count-up stats block, or a generic numbered "01/02/03" service-row list anywhere on the page, and never reveal content with a plain y+opacity fade — every entrance below uses clip-path wipes, needle sweeps or blur+opacity instead.
## The shared radial-placement primitive
Every gauge on the page — the hero dial's tick ring, the six mini preset-dials, the four semicircle spec gauges — is built from one formula, reused everywhere: a zero-size anchor positioned at the gauge's true pivot (`position:absolute; top:<pivotY>; left:50%; width:0; height:0`), with each tick/label child positioned `top:0; left:0` and given `transform: translate(-50%,-50%) rotate(angleDeg) translateY(-Rpx)` (append a trailing `rotate(-angleDeg)` before the child renders if it is text that must stay upright, e.g. the hero's frequency labels). Needles that must be rooted at the pivot instead use plain top/left/height positioning with `transform-origin: bottom center` and only `transform: rotate(angleDeg)`.
## Signature 1 — the hero dial: drag/wheel rotation with exponential inertia and a "vernier" snap
The hero's tuning knob is a `320px` static tick-ring (non-rotating) with a `208px` rotating knob centered on top. The tick ring has three graduation layers: 120 fine "vernier" ticks every `3deg` rendered as a single `repeating-conic-gradient(from 0deg, rgba(243,236,221,0.42) 0deg 0.6deg, transparent 0.6deg 3deg)` disc masked to a thin annulus (`mask-image: radial-gradient(circle, transparent 60%, black 62%, black 74%, transparent 76%)`) — never 120 individual DOM nodes; 12 coarse ticks every `30deg`; and 6 station-frequency labels every `60deg` at a larger radius, one per preset. The knob itself has a knurled rim (a masked `repeating-conic-gradient` stripe pattern) and a single `3px`-wide accent needle running from near its rim to its center, so the needle is carried "for free" whenever the knob's own transform is set — never animate the needle separately from its parent knob.
Rotation is tracked as one plain number (`rot.deg`, unwrapped/accumulated, never reset to 0–360). Pointer drag computes the angle from the pointer to the dial's center via `atan2`, accumulates the shortest-path delta into `rot.deg` every `pointermove`, and derives an instantaneous angular velocity from `delta / dt`, clamped to `±900deg/s`. On release, if `|velocity| > 6deg/s` the dial free-spins in a bounded `requestAnimationFrame` loop (not an always-on loop — it only runs during this finite coast): each frame, `rot.deg += velocity*dt` and `velocity *= Math.exp(-2.6*dt)` (exponential damping, so ~9% of the release velocity remains after 1 second). Once `|velocity|` drops below `6deg/s` the coast ends and a GSAP tween eases `rot.deg` to `Math.round(rot.deg/3)*3` — the nearest 3° "vernier" graduation — over `0.42s` with ease `back.out(1.8)` (a small overshoot-then-settle that reads as a mechanical click). Mouse-wheel input over the dial calls `preventDefault()` and instead of moving the rotation directly, adds an impulse of `-deltaY * 0.4` degrees/second to the same velocity variable, which then runs through the identical coast-and-snap pipeline — so wheel and drag feel like the same physical object. The dial is also a real `role="slider"` with `tabindex="0"`; ArrowUp/ArrowRight and ArrowDown/ArrowLeft jump exactly one preset (`60deg`) via the shortest rotational path, Home/End jump to the first/last preset. On mount, before any interaction, the needle sweeps in once from `-130deg` to `0deg` over `0.9s power3.out` (delayed `0.2s`) as a one-time "power-on" flourish — not a scroll reveal.
## Signature 2 — the frequency-style LCD readout
Six presets sit every `60deg` around the dial: 88.3 MHz "Terra" (field recordings, curator R. Voss, 42 min, key A), 91.5 "Nocturne" (late-hour ambient, M. Iida, 58 min, F♯), 94.9 "Copper" (vintage soul, L. Okafor, 37 min, D), 98.2 "Glass" (minimal/cold reverb, A. Renn, 45 min, C), 101.6 "Velvet" (low-gain jazz, S. Marchetti, 51 min, B♭), 104.9 "Iron" (industrial rhythm, K. Dahl, 40 min, E). The current preset index is derived every frame as `Math.round(wrap360(rot.deg)/60) % 6`. A dark LCD panel (`linear-gradient(180deg,#14100D,#0B0807)`, inset shadow, a slow `4.2s` ambient box-shadow "backlight" pulse) shows the frequency in large tabular-figure monospace with an accent glow, the preset name, its one-line tag, and a footer row of curator / runtime / key — plus a small "PRESET 0n/06" counter. Six small dots below the dial mirror the current preset (the active one filled accent) and are independently clickable to jump the real dial via the shortest rotational path.
## Signature 3 — needle-and-tick instrument language, reused below the fold
Section "On the dial" (id="presets") repeats the six presets as cards, each with a small non-interactive replica dial (12 ticks, one needle) whose needle is set on load to `-100deg` and, on scroll entry, sweeps to that preset's true angle (`i*60deg`) over `0.8s power3.out` while the card itself wipes open via `clip-path: inset(0 100% 0 0) → inset(0 0% 0 0)`, `0.7s power3.out`, staggered `0.06s` per card through `ScrollTrigger.batch` (`start:"top 88%"`). Clicking a card snaps the real hero dial to that preset and scrolls back to it. Section "The Hardware" (id="instruments") shows four products — Vernier One FM/AM Tuner ($1,240, ±0.05 MHz drift/8h), Meridian 40 integrated amplifier ($2,180, 40W×2 Class-A first watt), Low Arc direct-drive turntable ($1,890, 0.03% wow/flutter), Fathom 5 standmount monitor pair ($1,560, 45Hz–22kHz ±1.5dB) — each card opens with a transparent product cutout sitting directly on the panel color (walnut-and-aluminum hardware with a knurled dial as the visual hero; in this standalone build draw it as a simple CSS/SVG silhouette rather than loading an image — no external images allowed; give it a CSS `drop-shadow` and a small `translateY` lift on card hover), followed by a semicircular spec gauge: 11 ticks every `18deg` across a `-90deg` to `+90deg` sweep, a needle mapped from a 0–100 "reading" (`78, 64, 91, 55`) via `angle = -90 + reading/100*180`, revealed with the identical clip-path-wipe-plus-needle-sweep pattern (`0.8s`, staggered `0.07s`).
## Signature 4 — background hue tied to accumulated rotation
A soft radial aura behind the hero copy (`hsl(hue,72%,46%)` fading to transparent, gently breathing via a `6s` opacity keyframe) reads its hue from a CSS custom property `--vnr-hue`, recomputed every physics frame as `(8 + rot.deg * 0.65) mod 360` — the accent's own hue (`8°`, matching `#E0533D`) as the baseline, shifting `0.65deg` of hue per degree of accumulated dial rotation, so one full `360deg` physical turn shifts the aura through roughly `234deg` of hue. The same variable drives the dial-face's outer glow and the footer's slowly turning dashed dial silhouette (`60s` linear infinite, radius `62vh`), so the footer visibly "remembers" however far the hero dial has been spun. On the footer CTA's hover, nudge `rot.deg` by `+5deg` and back (`0.5s sine.inOut`, yoyo, one repeat) so the real hero dial visibly twitches — a small cross-section callback.
## Section: Calibration (id="calibration")
A frequency-scale strip mimics a vintage tuner's glass: 101 ticks from 88.0 to 108.0 MHz in `0.2` steps (`22px` apart), a labeled major tick every `2.0` MHz. This section pins (`ScrollTrigger`, `pin:true`, `start:"top top"`, `end:"+=160%"`, `scrub:0.6`) while a fixed center needle (with a flickering accent LED, `2.4s` keyframe) stays still and the whole scale strip translates horizontally under it in proportion to scroll progress. Four spec lines crossfade in quarter-progress buckets (`0.35s` opacity): "Signal-to-noise ratio 92 dB", "Total harmonic distortion 0.015%", "Capture range ±75 kHz", "Frequency response 20 Hz–20 kHz ±0.5 dB".
## Section: Transmission Log (id="log") and Footer
Five dated workshop-log entries (LOG — 03.02 through 07.30, real-sounding bench notes about recalibration, listening sessions and shipping, each attributed to "WORKSHOP, KYOTO" or similar), each row revealed with a left-to-right `clip-path` wipe (`0.7s power3.out`, `0.08s` stagger) — never a fade-up. The footer repeats the eyebrow/heading treatment, a mailto CTA "Request an audition ↗" that triggers the dial nudge on hover, and a meta row ("VERNIER AUDIO WORKS © 2026" / "KYOTO — MILAN — WORKSHOP LOG").
## Scroll animations (shared heading treatment)
Every section heading is: a 16px tick-shaped icon (a conic-gradient wedge) rotating in from `-90deg` to `0deg` (`0.5s back.out(2)`), an eyebrow sliding in on x (`-10px → 0`, `0.5s power2.out`), and the title itself wiping open via `clip-path` (`0.6s power3.out`), fired together with small staggered delays on `ScrollTrigger` `start:"top 85%"`, `toggleActions:"play none none reverse"`. Supporting copy (ledes, hero sub-text, footer meta) uses a distinct secondary treatment — `opacity:0 + blur(4px) → opacity:1 + blur(0)`, `0.6s power2.out`, `0.06s` stagger via `ScrollTrigger.batch` — kept visually different from both the heading wipe and the card needle-sweeps.
## Performance & accessibility
The rotating knob writes exactly one `transform` string per frame; the coast `requestAnimationFrame` loop only runs during the bounded post-release inertia window, never as an always-on loop. Respect `prefers-reduced-motion`: disable the aura breathing, LCD pulse, needle glow, LED flicker and footer spin keyframes; skip the inertial coast entirely (snap immediately, `0.16–0.25s power2.out`); skip the calibration pin/scrub (show the first spec statically); and render every scroll-triggered element already in its resting state. The dial is a real focusable `role="slider"` reachable and operable by keyboard; preset dots and cards are real buttons with descriptive `aria-label`s; set `user-select:none` and `touch-action:none` on the dial's hit area so dragging never triggers native text selection on the surrounding tick labels. All brand names, products, people and log entries are original and fictional.
## Action flow and content
Implement the following local planning experience for the primary CTA, in the visual language of the page. Use a real button opening a labelled modal dialog. Choosing a pricing card must preselect that exact plan. A navigation link may move to another section; a planning CTA must lead to its review flow.
Use this content for the dialog, including the option details and notes:
{
"slug": "dial-select",
"brand": "VERNIER AUDIO",
"accent": "#a74835",
"title": "Shape your listening session",
"intro": "Choose a component and record the room, music and questions you want to bring to an audition.",
"facts": [
[
"Listening",
"Use familiar recordings to compare components."
],
[
"Before a visit",
"Confirm the component, connections and session availability."
],
[
"After listening",
"Keep impressions alongside the equipment and room conditions."
]
],
"groups": [
{
"label": "Component",
"options": [
{
"title": "Vernier One",
"detail": "FM / AM tuner · concept price $1,240."
},
{
"title": "Meridian 40",
"detail": "Integrated amplifier · concept price $2,180."
},
{
"title": "Low Arc",
"detail": "Direct-drive turntable · concept price $1,890."
},
{
"title": "Fathom 5",
"detail": "Standmount monitor pair · concept price $1,560."
}
]
}
],
"date": true,
"brief": "Describe your room, present system and the recordings you would like to hear.",
"notes": [
"Illustrative component specifications. No listening appointment or purchase is confirmed."
]
}
- Explain before input that this is a fictional brand sample: choices can be reviewed and saved, with no external submission, booking, payment or registration. Use each brand's language. Do not launch a mail client or present an installer for a fictional product.
- Give every option group a legend, inputs explicit labels and errors linked descriptions. Validate options against the allowed values, requested dates as actual dates from today onward, and free text as 10–2,000 trimmed characters. Blank spaces alone must fail. Tracking accepts the sample reference TG-2048 only.
- Focus the first invalid field and preserve every entered value. On success, show the selected option WITH its full detail, requested date or brief, relevant facts and notes. An edit action returns to the preserved form. Do not claim a real reservation, purchase or account has succeeded.
- Save the complete review as UTF-8 text. A browser download request is not proof of a file being written. On download failure, retain the full text in a labelled, selectable textarea and offer retry. Do not show a false success state.
- Constrain modal content to the viewport with internal scrolling. Support keyboard and touch, trap focus while open, close on Escape and restore focus to the exact initiating control. Keep these operations available with motion disabled.
- If a separate project-contact CTA is present, let it collect a project brief and review it locally; a product selection CTA must retain the product choice. Verify both flows independently.