枠の中でスクロール・クリックして動きを試せます。端末指定は実寸表示です。幅が足りない場合は横にスクロールできます。
再現プロンプト
架空の醸造所サイト。スクロールに連動してあらゆる容器の液面が波打ちながら上昇し、沈んだホップや麦芽が揺らぎ、満水になると次のセクションへ溢れ出す。 配色・構成・動きの数値をまとめた指示書です。 お使いのAIに貼り、素材やお店の情報を伝えて実装してください。仕上がりは利用するAIと素材によって変わります。
Build a single self-contained HTML file (inline CSS/JS; GSAP + ScrollTrigger from a CDN is the only allowed dependency, no external images) for "COPPERLINE BREWING CO.", a fictional small-batch brewery. The page's whole motion language is "container and water level": every visual is an actual drawn vessel (fermenter, glass, jar, gauge tube) whose liquid rises with scroll — never a decorative shape. The page scrolls normally with the window.
## Art direction
- Background: near-black brew-house brown #12100E for hero/brew-line/flight/cellar; a warmer #1C1410 for the taproom-and-events section and the footer.
- Text: main #F5F1EA, muted #B8A996, accent (every gauge/CTA) #4FC3B7.
- Liquid palette: house ale #C9822F over deep #7A4A16; mash #D9A441/#8A5F1E; boil #B5651D/#6E3A10; ferment #8C4A1E/#4E2710; condition reuses the house-ale colors (a closing callback). Amber foam highlight #F3E7C9. Tasting-flight liquids: pale #E0932E/#8A5518 foam #FFDFA0; stout #1B120D/#050302 foam #D8B48C; wheat #E9C46A/#A6822C foam #FFF6DD; sour #D6567C/#8C2F4D foam #FFE1EA.
- Typography: system sans for headings/body (weight 700-800 headings), ui-monospace for eyebrows/labels/readouts, letter-spacing 0.24-0.3em on eyebrows.
- Every vessel shares one border: 1px solid rgba(79,195,183,0.35), inset shadow 0 0 22px rgba(0,0,0,0.4), a top glass highlight (inset 0 1px 0 rgba(255,255,255,0.16), inset 0 -1px 0 rgba(0,0,0,0.4)).
## The shared "vessel" primitive (reuse everywhere)
Build this once and reuse it for the hero fermenter, the fixed sight-glass gauge, the four brew-line tanks, the four tasting glasses, the cellar jar, and the overflow divider:
1. A fill layer sized by a CSS custom property '--level' (0..1): 'height: calc(var(--level) * 100%)', 'position:absolute; left:-2px; right:-2px; bottom:0;', 'background: linear-gradient(180deg, var(--liquid), var(--liquid-deep))'.
2. A wave surface: two SVG tiles pinned to the top of the fill via 'transform: translateY(-50%)', each 'width:200%', viewBox "0 0 300 32" containing 2 wavelengths built from cubic-bezier segments (per 150px period: 'C {x+37.5},{top} {x+112.5},{bottom} {x+150},{mid}', mid=16). Layer A: amplitude 12px (top 4, bottom 28), liquid-colored, loops 'translateX(0 -> -50%)' over 3.6s linear infinite. Layer B: amplitude 7px (top 9, bottom 23), foam-colored, opacity 0.5, loops the reverse direction over 5.4s linear infinite — two counter-scrolling wave tiles, never a flat edge.
3. Rising bubbles: small circles (radial-gradient white highlight), size 3-9px randomized, animated only via 'transform: translate(driftPx, -travelPx) scale(1.15)' plus opacity (GPU-safe, never the 'bottom' property), duration 3.2-6.8s linear infinite, drift +/-14px, and a NEGATIVE random animation-delay (0 to -6.8s) so bubbles are already mid-flight on first paint. Counts: hero 18 (travel 360px), gauge 6 (travel 220px), each tasting glass 8 (travel 170px), cellar jar 10 (travel 260px).
4. Optional submerged children (hop cone / grain cluster / yeast swirl / cherry, small inline SVGs) positioned 'bottom: {depth*100}%', depth a 0..1 fraction of vessel height, tagged with a data-depth attribute. A shared helper compares the vessel's current --level to each depth on every update and toggles a "submerged" class.
## Refraction / wobble filter (submerged elements shimmer)
One SVG filter, used by every submerged icon: a feTurbulence (type="fractalNoise", numOctaves="2", seed="4", baseFrequency="0.012") with a child animate element on attributeName="baseFrequency", values="0.012;0.024;0.012", dur="6.4s", repeatCount="indefinite", feeding a feDisplacementMap (in="SourceGraphic", in2="noise", scale="6", xChannelSelector="R", yChannelSelector="G"). Once submerged: apply that filter plus saturate(1.15) brightness(0.88) and scale(1.05) to the icon (0.5s transition), and fade in a multiply-blend liquid-tint disc behind it (opacity 0 -> 0.4). Dry elements render plain.
## Section 1: Hero
Eyebrow "COPPERLINE BREWING CO. · SMALL-BATCH ALE". H1 (clamp 2rem-3.4rem, weight 800, max-width 20ch): "We brew until the tank tells us to stop." Hero fermenter vessel (~260×300px, border-radius 20px 20px 30px 30px), starting level 0.06, with a hop cone at depth 0.28/left 35% and a grain cluster at depth 0.55/left 65%. Sub-copy (max 46ch, muted): "Every fermenter on our floor carries a sight-glass and nothing else. When the line's full, the batch is done — no clocks, no shortcuts, just the level rising at its own pace." Pulsing scroll cue "↓ Watch the level rise" (opacity 0.4-1, 2.6s infinite).
## Section 2: The Brew Line
Eyebrow "THE BREW LINE // FOUR STAGES", H2 "From grain to glass, read at every stage." A 4-column grid (2 columns under 780px) of stage tanks (120×150px, border-radius 10px 10px 16px 16px): MASH 22% ("Grain steeps at 66°C for 60 minutes."), BOIL 48% ("Hops dropped in three additions over 90 minutes."), FERMENT 74% ("House yeast, 18°C, 12 days on the sight-glass."), CONDITION 96% ("Cold tank, 21 days — then the line's full."), each with a static "NN%" readout. On scroll-enter (start "top 78%", toggleActions "play none none reverse"), --level tweens 0 to target over 1.3s with ease elastic.out(1,0.65) (a pour-settling overshoot), staggered 0.18s.
## Section 3: Tasting Flight
Eyebrow "TASTING FLIGHT // FOUR POURS", H2 "Four glasses. Four lines. Hover to pour a little higher." Four glasses (96×160px each) with four DISTINCT real-glassware silhouettes: a tall slim pilsner cone, a nonic pint with its bulge in the top third, a waisted weizen curve, and a stemmed tulip (round bowl + flared rim — the only footed glass). Each glass is a 3-layer sandwich so the liquid reads as sitting INSIDE real glass: (1) back layer, the empty glass itself — outline, wall shading, base shadow (in the original build this is a magenta-keyed photoreal cutout; in this standalone build draw it as a layered SVG/CSS glass shell instead — no external images allowed); (2) middle layer, the shared vessel fill (liquid + waves + bubbles + garnish) masked to that glass's inner-wall shape via clip-path/mask-image so the pour never crosses the walls — for the tulip the mask covers the bowl only (interior floor ~0.32 up; stem and foot stay solid glass); (3) front layer, a highlights-only copy of the same glass (rim light + one vertical specular streak) with mix-blend-mode: screen and opacity ~0.6, so the sheen sits ON TOP of the beer. Pours: FIRST POUR (Pale Ale 5.2%, level 0.62, hop cone depth 0.3), DEEP LINE (Oat Stout 6.4%, level 0.88), HIGH CLOUD (Wheat Ale 4.8%, level 0.54), RED LINE (Berry Sour 4.1%, level 0.4, cherry depth 0.38 — just above the tulip's bowl floor). Entrance: same fill, 1.1s power2.out, staggered 0.14s. Hover (required mouse reactivity): pointerenter tweens --level up +0.14 (capped at 1) over 0.6s power2.out; pointerleave tweens back to base over the same duration.
## Section 4: The Cellar
Eyebrow "THE CELLAR // WHAT GOES IN", H2 "Hops, grain, and time — nothing else." One larger jar (200×240px, border-radius 26px, small teal lid bar) filling to 0.72 over 1.7s power2.out on scroll-enter, holding three submerged items that cross the waterline in sequence as it fills: hop cone depth 0.30/left 28%, grain cluster depth 0.48/left 62%, yeast swirl depth 0.64/left 45%. The jar also tilts toward the cursor on pointermove (rotateZ = relX*6deg, rotateX = -relY*6deg, perspective ~700px, 0.5s power3.out; resets over 0.7s on pointerleave) — the second required mouse interaction. Copy: "Watch the line pass the hop cone, then the grain, then the yeast — each one only shows its true color once it's under the surface."
## Section 5: Taproom & Events
Warm background #1C1410. Eyebrow "TAPROOM & EVENTS // THIS WEEK", H2 "Pull up a stool. The line's always moving." A stacked list (max-width 560px) of four rows, each with a name plus a status pill (teal border "OPEN", amber #E6A64A border "FEW LEFT"), a time line, an 8px pill occupancy bar (track rgba(255,255,255,0.08), fill linear-gradient(90deg, #4FC3B7, #C9822F) driven by --level), and a static caption (e.g. "30 / 40 seats poured" — plain text, never an animated counting digit). Rows: TRIVIA NIGHT (Thu 7pm, 0.75, OPEN), CASK NIGHT (Fri 6pm, 0.50, OPEN), LIVE ON THE FLOOR (Sat 8pm, 0.92, FEW LEFT), FOUNDERS' TOUR (Sun 11am, 0.34, OPEN). Bars fill on scroll-enter, 1.0s power1.out, staggered 0.12s.
## Overflow transition (full at the line, spills into the footer)
Between Taproom and Footer, insert a wall-less, full-width 150px strip using the vessel primitive (no border/radius, house-ale liquid). Its --level is scrubbed (ScrollTrigger scrub 0.6, start "top 95%", end "bottom 40%") to its own entry into view. Once progress crosses 0.85, fire a one-shot staggered fall of 6 teardrop drips (7×18px, house-ale color) from the strip's top to +130px, power1.in over 0.9s, staggered 0.09s, then reset invisible; scrolling back above progress 0.5 re-arms the trigger so scrolling down again replays the spill.
## Footer
Warm background continues from the overflow strip's color. H2 "The tank's full. Come find the line yourself." Copy: "Visit the taproom, or have a case brewed to your line." Pill CTA "Visit The Taproom →" (1px solid #4FC3B7 border, transparent fill; hover fills #4FC3B7, text turns #0B1615, translateY(-2px), 0.3s ease). Closing monospace log line: "BATCH SIGHTLINE · 100% · 14.8°P".
## Persistent instrument (hero to footer)
A fixed sight-glass gauge on the right edge (vertically centered, hidden under 680px width): a 30×210px tube (vessel primitive, 6 bubbles, travel 220px), a vertical "LEVEL" label, and a live readout below. One ScrollTrigger pinned to the document (start "top top", end "bottom bottom", scrub: true — no easing) writes --level = 0.06 + progress*(1.0-0.06) onto this gauge AND the hero fermenter simultaneously (lock-step rise), plus two live readouts: fill percent (Math.round(level*100) + "%") and a °Plato gravity reading interpolated 2.0 to 14.8 ((2.0 + progress*12.8).toFixed(1) + "°P"). This is a live instrument reading scroll position directly, never an animated count-up tally.
## Scroll animations (entrance language for every heading/eyebrow/paragraph)
No generic fade-up anywhere. Every text node starts hidden behind a wavy clip-path polygon covering it from the bottom, then "fills up" to reveal it — the same liquid-fill idea applied to typography. Each tween frame recomputes 10 polygon points across the width (9 segments): y = (100 - revealPercent) + sin((i/9)*2*PI + phase)*3.4, clamped to [-10,100], plus 2 fixed bottom corners; opacity runs in parallel as min(1, revealPercent/30). On enter (start "top 78%", toggleActions "play none none reverse"): revealPercent 0 to 100 over 1.0s power2.out, staggered 0.14s per element, each offset by phase = index*0.8 so a group doesn't wobble in unison; reverse 100 to 0 over 0.35s power1.in on leave-back.
## Performance & accessibility
Everything is transform/opacity/clip-path CSS plus a handful of ScrollTrigger instances — no canvas, no per-frame JS loops beyond scrub callbacks. Respect prefers-reduced-motion: reduce by disabling the wave loop and bubbles, freezing the turbulence animate element, shortening entrance tweens to ~0.3s, and skipping the drip burst. Every decorative SVG/span is aria-hidden; the CTA has a visible focus ring (2px solid #4FC3B7, 3px offset); body-text contrast meets AA against both background tones. Cap bubble counts as specified and never animate layout properties (height/width/bottom) outside the cheap --level custom-property reads inside calc(), to hold 60fps on a mid-range laptop.
## 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": "tide-gauge",
"brand": "COPPERLINE BREWING CO.",
"accent": "#826125",
"title": "Make time for the taproom",
"intro": "Compare a relaxed tasting with a guided look at the brewing process, and save the practical details for your visit.",
"facts": [
[
"Opening hours",
"Thursday–Friday 16:00–22:00 · Saturday 12:00–22:00 · Sunday 12:00–18:00"
],
[
"Seating",
"Walk-in benches and a step-free ground-floor tasting room"
],
[
"Alternatives",
"Alcohol-free drinks and water available"
]
],
"groups": [
{
"label": "Visit",
"options": [
{
"title": "Tasting flight · $14",
"detail": "Four 100 ml pours selected at the counter. Allow about 45 minutes."
},
{
"title": "Brewery introduction · $24",
"detail": "A 30-minute guided session followed by a tasting flight. Alcohol-free alternative available."
}
]
}
],
"date": true,
"notes": [
"Fictional venue and hours. A real visit page would include a verified street address, transport directions and current availability. This sample saves a visit plan only."
]
}
- 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.