枠の中でスクロール・クリックして動きを試せます。端末指定は実寸表示です。幅が足りない場合は横にスクロールできます。
再現プロンプト
架空のレコードショップ「SUNDIAL RECORDS」を、ドラッグ/ホイールで慣性つきに送るCSS 3Dカバーフロー棚として再現したLP。ジャケットはローカルAI生成画像。 配色・構成・動きの数値をまとめた指示書です。 お使いのAIに貼り、素材やお店の情報を伝えて実装してください。仕上がりは利用するAIと素材によって変わります。
Build a single self-contained HTML file (inline CSS/JS; GSAP from CDN optional) for "SUNDIAL RECORDS" — a fictional used-vinyl shop. The page is a physical-shelf metaphor: browsing the whole catalogue is one continuous 3D "cover flow" (CSS 3D transforms + plain JS physics, no WebGL). Covers are 12 locally-hosted, AI-generated square images (see "Imagery" for the per-sleeve prompts) — no external CDN, no text baked into the artwork (titles/artists/genre are DOM overlays).
## Art direction
Background: near-black #0A0A0C base with a full-bleed backdrop layer that continuously cross-fades toward a darkened wash of whichever record is currently centred (see "Background sync" below), plus a fixed radial vignette (120% 90% ellipse at 50% 0%, transparent to rgba(0,0,0,0.55)) over the top for text contrast. Foreground text colour #F5F1EA. Accent (every button, kicker, dashed line, active state): #F06543. Headings use a serif display stack (Georgia, 'Times New Roman', serif); body copy uses a sans stack ('Helvetica Neue', Arial, ui-sans-serif, system-ui, sans-serif). Page max-width 1040px, centred.
## The record catalogue
Define 12 fictional records: id, artist, title, year, genre, a one-sentence liner note, an image path, and a "dominantColor" hex hand-picked from the artwork (drives background sync, sleeve border, and vinyl-label colour). Records (artist / title / year / genre / dominantColor):
- Marigold Static / "Low Tide Radio" / 1979 / Soul / #D9682C
- The Nightshift Quartet / "Aftershift" / 1986 / Jazz-Funk / #1C6B70
- Ionsphere / "Chrome Weather" / 1983 / Synth-Wave / #4B2E86
- Paper Moths / "Every Room Is Blue" / 1991 / Dream Pop / #3A6A9E
- Hotel Casablanca / "Disco At The Coastline" / 1978 / Disco / #241C52
- Sable & Ora / "Quiet Machinery" / 1995 / Ambient / #B7B2A2
- Concrete Larks / "No Sirens Tonight" / 1981 / Post-Punk / #241214
- Deja Voodoo / "Midnight Boogie Freight" / 1980 / Boogie / #34204A
- Harbor & Halo / "Neon Provinces" / 1988 / City Pop / #E4864F
- Roots Transmission / "Signal From The Deep" / 1976 / Dub / #14301F
- Wren Hollow / "Fieldnotes, Vol. II" / 1972 / Folk / #B9A87C
- Loft 4B / "Basement Transmission" / 1990 / House / #A81C6E
Each sleeve is 210×210px: image fills it via object-fit: cover, 1px border tinted with dominantColor, a genre corner tag (dark pill, top right), and a bottom gradient-scrim label with artist (0.62rem) and title (bold, 0.78rem) as DOM text over the image — never baked into the artwork.
## Imagery
AI-generate these 12 original square (1:1) sleeves (or substitute similar original artwork) — NO text, logos, or watermarks in any of them; all copy is added afterward as DOM overlays:
1. "1979 soul sleeve, ocean sunset, concentric orange sun rays and wave bands, cream-to-rust gradient, vintage paper grain, flat mid-century style"
2. "1986 jazz-funk sleeve, art deco geometric abstraction, overlapping teal and mustard-gold circles and stepped triangles on black, bold flat shapes"
3. "1983 synth-wave sleeve, retro-futuristic neon grid horizon under a starry purple-magenta sky, glowing horizon, airbrushed 1980s sci-fi poster style"
4. "1991 dream pop sleeve, monochrome indigo watercolor wash of a hazy sunlit room, window and soft furniture silhouettes, blurred dreamlike edges"
5. "1978 disco sleeve, mirror ball over a glittering night coastline, diamond confetti sparkles in pink/cyan/gold, shoreline lights on dark water"
6. "1995 ambient sleeve, delicate technical pencil diagram of an antique measuring apparatus on aged cream paper, muted pastel accents"
7. "1981 post-punk sleeve, high-contrast B&W photocopy alley photo, sharp triangular shadow on concrete, fire-escape silhouette, one red neon streak"
8. "1980 boogie sleeve, night freight train lit by warm headlights, dramatic purple-orange sky with glowing moons, retro airbrush motion streaks"
9. "1988 city pop sleeve, elevated highway over a dusk skyline, pastel orange-pink sunset over indigo buildings, gouache travel-poster style"
10. "1976 dub sleeve, near-black background, faint glowing dark-green concentric ripples like sonar rings, minimal and murky"
11. "1972 folk sleeve, botanical field-notebook illustration of wildflowers in fine ink linework and light watercolor, faint contour lines, tan paper"
12. "1990 house sleeve, abstract magenta/cyan light beams and geometric fragments radiating from a bright core on near-black, rave-poster energy"
Format each: square, no text/logos. Save locally as WebP (~800×800, ≤300KB each) and reference with plain <img> — never fetched at runtime.
## Section 1: Hero + the Cover Flow shelf
Kicker "EST. 1994 · CRATE-DUG, NOT ALGORITHM-FED", H1 "SUNDIAL RECORDS" (clamp(2.1rem,6vw,3.6rem)), one-sentence sub-copy, then the shelf itself, centred, min-height 100vh section.
### Shelf geometry (fixed, named constants)
- perspective: 1100px on the stage container.
- Cover size: 210×210px square sleeves.
- One continuous scalar 'pos' (float) is the "index position" of the shelf (0 = first record, 11 = last). For every record i, compute offset 'o = i - pos', 'absO = |o|':
- rotateY = -sign(o) * 58deg * min(1, absO) — flat (0deg) exactly at the centred record, ramping linearly to a fixed 58° for any neighbour one full index away or further (continuous, no discontinuity).
- translateZ = -190px * min(1, absO) — pushes neighbours back into the distance, capped at 190px.
- translateX = o * 150px — a constant 150px horizontal spacing per index unit.
- "Settle lift": liftT = max(0, 1 - absO / 0.5); translateY = -16px * liftT; base scale (1 - 0.064 * min(5, absO), falling linearly to 0.68 by 5 units away) gets an extra ×(1 + 0.05*liftT) — the centred record continuously lifts 16px and grows 5%, purely as a function of 'o' (no separate "open" transform).
- opacity = clamp(1 - (absO - 4), 0, 1) — covers stay fully opaque until 4 index-units away, then fade out over the last unit (covers beyond 5 units are invisible).
- brightness filter = max(0.45, 1 - absO*0.11) for depth-cueing.
- z-index = round(1000 - absO*10) so the centred cover always draws on top.
- The whole 3D stage has '-webkit-box-reflect: below 6px linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 45%, rgba(0,0,0,0.35) 100%)' — a genuine reflected floor of the live 3D scene, not a static image.
- The stage wrapper gets a uniform CSS 'scale()' from 'clamp(containerWidth / 900, 0.5, 1)' via ResizeObserver, so the whole 3D scene shrinks on small screens without altering the geometry math. An outer wrapper permanently sways (rotateZ ±0.6deg, translateY 0/-3px, 10s ease-in-out infinite) so the shelf is never static.
### Input + physics
- Pointer drag: 1px of horizontal drag = 1/150 index units (i.e. dragging 150px moves exactly 1 record). Dragging past either end is resisted to 35% of the excess distance (rubber-band).
- Velocity is sampled every pointermove as Δposition/Δtime(ms). On release (non-reduced-motion), coast: 'pos += velocity*dt; velocity *= 0.93^(dt/16.7)' until |velocity| ≤ 0.0006 index-units/ms, then lock a settle target = nearest integer index and ease 'pos' toward it at 'min(1, 0.16*(dt/16.7))' per frame (exponential spring, not a fixed-duration tween). Whenever 'pos' drifts past [0, 11], pull the excess back by 22% every 16.7ms-equivalent (soft return, not a hard clamp).
- Horizontal wheel/trackpad gestures (only when |deltaX| > |deltaY|, so vertical page scroll is never hijacked) nudge 'pos += deltaX * 0.0022', clear any settle target, and start a fresh settle 140ms after the last wheel tick.
- Prev/Next buttons and ArrowLeft/ArrowRight (shelf is a focusable 'role="listbox"', 'tabIndex=0') jump the settle target to the neighbouring integer index. Clicking a non-centred cover jumps to it, unless the pointer moved over 6px first (a drag, not a click).
- When 'pos' is within 0.002 of its settle target and velocity is at rest, the shelf is "open": a vinyl-disc SVG (grooved rings, centre label = dominantColor) slides from behind the sleeve — translateX -40px, rotate 100deg, scale to 1, opacity to 1, 0.6s back.out(1.6) — while the title/artist/year/genre/note panel reveals via clip-path wipe ('inset(0 100% 0 0)' → 'inset(0 0% 0 0)' + opacity), 0.55s power2.out, 0.08s stagger across the four lines. Dragging away reverses both instantly (0.3s power2.in).
### Background sync
Every time the shelf settles on a new record, tween the backdrop's background-color to that record's dominantColor darkened to 22% of its RGB value ('rgb(r*0.22, g*0.22, b*0.22)') over 0.8s power2.out.
## Section 2: Mission
Heading "We still believe in the run-out groove." Two short paragraphs about buying whole estate-sale collections rather than chasing algorithmic "similar" tags — every record is vetted by a staff member on an actual turntable before it reaches the counter.
## Section 3: This week at the counter (staff picks)
A responsive grid ('repeat(auto-fit, minmax(220px,1fr))') of 5 picks, each showing a small 56×56px cover-art thumbnail (the same locally-hosted image, object-fit: cover), the artist/title, a one-line staff quote, and "— picked by [name]". Cards sit inside a 'perspective: 900px' container and start at a static 'rotateY(-8deg)' (even-indexed cards '+8deg'), straightening to 'rotateY(0) translateZ(14px)' on hover over 0.35s ease — a smaller, hover-driven echo of the hero shelf's 3D tilt language, not a duplicate of the drag mechanic.
## Section 4: Live at the counter (in-store sessions)
4 rows styled as dashed "ticket stubs" (1px dashed accent border, two circular cut-out notches on the left/right edges via absolutely-positioned background-coloured circles) each showing a date, the performer, and the time/price — no numbering, differentiated by date only.
## Section 5: Footer — The Crate Club
Kicker "THE CRATE CLUB", heading "Get first pick before it hits the shelf.", one paragraph, a pill CTA "Join The Crate Club →" (1px accent border, hover inverts to solid accent fill + dark text + translateY(-2px)), and a small store-hours log line.
## Shared reveal languages (used on every non-shelf section, never a plain fade-up)
"Sleeve wipe" for every heading/kicker/CTA: starts 'clip-path: inset(0 100% 0 0)' + opacity 0; on ScrollTrigger enter ("top 78%" of the internal scroll container, toggleActions "play none none reverse") animates to 'inset(0 0% 0 0)' + opacity 1 over 0.7s power3.out with a 0.12s stagger (reverses over 0.25s power2.in on scroll-back) — no y-offset, reads as pulling a sleeve out of its slot.
"Grain fade" for every paragraph of body copy: starts 'filter: blur(6px)' + opacity 0; same trigger, animates to blur(0px) + opacity 1 over 0.8s power2.out with a 0.1s stagger — again no y-offset.
## Performance & accessibility
Respect 'prefers-reduced-motion': skip the idle sway and coast/rubber-band physics (jump straight to a fast settle-spring on release), shorten vinyl-slide/text-wipe/sleeve-wipe/grain-fade to ~0.2–0.3s, and keep background/detail-panel updates (state, not decoration). All 12 covers are 'loading="lazy"' WebP images (~800×800, ≤300KB) — no canvas, no runtime fetches. Per-frame work is minimal: one position update, one friction multiply, and a loop writing 'transform'/'opacity'/'filter'/'z-index' directly to each cover's style (no re-render in the hot path — state updates only on the rare "settle" transition). Clean up every rAF, native listener, ResizeObserver, and in-flight tween on unmount. Target 60fps at 1440px/dpr2.
## 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": "cover-flow",
"brand": "SUNDIAL RECORDS",
"accent": "#8b4d2d",
"title": "Inside the Crate Club",
"intro": "A quieter way to discover your next record. Choose the listening notes you would like to keep, then save your reading plan.",
"facts": [
[
"Membership",
"Free editorial club"
],
[
"Frequency",
"One monthly mixtape and one weekly stock note"
],
[
"What is included",
"Staff listening notes, grading notes and in-store session previews"
]
],
"groups": [
{
"label": "Your listening shelf",
"options": [
{
"title": "Jazz & soul",
"detail": "Small-label pressings, warm voices and deep catalogue discoveries."
},
{
"title": "Electronic & experimental",
"detail": "Ambient excursions, club records and independent electronic labels."
},
{
"title": "The mixed crate",
"detail": "An open-ended selection across genres, with a note from the buyer."
}
]
}
],
"notes": [
"Condition guide: M = unopened; NM = minimal signs of handling; VG+ = light cosmetic wear. Actual stock and grading would be checked before purchase.",
"Membership preference preview only. No email address is collected or mailing list created."
]
}
- 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.