MOTION PALETTE
← すべてのデモ

Peek List

InteractionImagery / GSAP / ScrollTrigger

フルスクリーンで開く ↗

枠の中でスクロール・クリックして動きを試せます。端末指定は実寸表示です。幅が足りない場合は横にスクロールできます。

再現プロンプト

白背景の作品インデックスをホバーすると行ごとに違う実写建築写真がカーソルに追従して浮かび上がる、架空アトリエPLINTHの1ページ。 配色・構成・動きの数値をまとめた指示書です。 お使いのAIに貼り、素材やお店の情報を伝えて実装してください。仕上がりは利用するAIと素材によって変わります。

Build a single self-contained HTML file (inline CSS/JS) for "PLINTH", a fictional architecture studio whose portfolio is a plain static index of project names. Hovering a row makes a real project photograph — a different one per row — float up near the cursor and lerp-follow it, tilting with pointer velocity, then shrink to nothing the instant the row is left. That single interaction is the whole identity of the page; every other section borrows the same "drafting sheet" language (corner registration ticks, hairline rules, a frame-closing-in reveal) so the whole page reads as one continuous drawing set — the photographs are simply the six sheets the index conceals until hovered. May use a CDN script for gsap; the page scrolls with the normal window. All six photographs are local files (see "## Imagery" for the exact generation prompt behind each), never a live fetch or external host.

## Art direction
- Paper background #FAFAF8, ink text #15140F (near-black, never pure #000), accent #A3E635 (a CAD/blueprint lime) used only for eyebrow labels, corner ticks and hover states. Headings in a serif (Georgia, "Times New Roman", serif) weight 700; body in the system sans stack; the preview's caption in a monospace stack.
- A 1px outer border (rgba(20,20,15,0.16)) frames the whole page. A fixed top nav (68px, translucent paper, 1px bottom hairline) shows wordmark "PLINTH" with a small "Architecture Studio" sub-label, links to Index / Practice / Process, and a pill "Commission →" button (1px ink border, fills ink on hover). A 2px progress bar under the nav fills accent lime as the page scrolls (scrub 0.3, trigger = full content height).
- Corner registration ticks: every major section (hero, index, practice, process cards, footer, and the photograph preview card) is 'position: relative' with four small 14px L-shaped marks (1.5px accent border on two adjoining sides) pinned to its four corners — a drafting-sheet motif repeated everywhere, including over the photographs, so real photography still reads as part of "one drawing set."
- Content column is centered, max-width 920px, with generous section padding (5rem top/bottom) and a 1px top hairline between sections.

## Section 1: Hero
Eyebrow "PLINTH — Architecture & Interiors, Est. 2014" (accent, 0.72rem, 0.3em tracking, uppercase). Serif H1 (700, clamp(2.4rem, 6vw, 4.2rem), line-height 1.04): "Buildings, indexed before they're built." Body copy (max-width 46ch): "Every project below is a plain line in a list — until you hover it. Then the photograph underneath surfaces: a facade at dusk, a stair core, a courtyard, held for as long as you stay." A "Scroll to the index ↓" cue scrubs opacity 1→0 across the first 40% of a screen-height of scroll, arrow bouncing translateY 0→5px over 1.8s ease-in-out infinite. Add one continuously-idle detail so the hero is never a static frame: a 1px horizontal accent gradient line that sweeps top-to-bottom across the hero (CSS keyframes, top 8%→92%, 5.5s linear infinite, opacity 0.55) — a "scanning" line, disabled under prefers-reduced-motion.

## Section 2: Index — the core mechanic
Eyebrow "Selected Works", H2 "An index, not a portfolio." Below it, six plain rows (no numbering, no "01/02/03" prefixes — name and metadata only), each paired with one local photograph: Kestrel Terraces (Housing, 2024, 01.webp, caption "Facade, dusk"), Basin Cultural Hall (Civic, 2023, 02.webp, "Timber frame, meadow"), Northgate Market (Mixed-Use, 2022, 03.webp, "Atrium, interior"), Vane House (Residential, 2024, 04.webp, "Stair core, plan view"), Concourse Pavilion (Landscape, 2021, 05.webp, "Courtyard, water"), Silo Works (Adaptive Reuse, 2020, 06.webp, "Study model"). Each row is a flex row (name left, "Type — Year" meta right in uppercase 0.78rem, 50%-opacity ink) with a 1px bottom hairline.

Row hover state ("indent + invert"): on pointerenter, the row gains an 'is-active' class that (a) animates 'padding-left' from 0 to 26px (ROW_INDENT) over 0.35s ease (ROW_INVERT_DURATION), and (b) reveals a '::before' pseudo-element filling the row with ink-black via 'transform: scaleX(0) → scaleX(1)' (transform-origin 0% 50%) over the same 0.35s, while the row's text color simultaneously transitions to the paper color — a background sweep that inverts the row from black-on-white to white-on-black as it indents. On pointerleave the class is removed and both transitions reverse.

Photograph preview (the page's signature): one reusable preview element — an absolutely positioned 280×360px (PREVIEW_WIDTH × PREVIEW_HEIGHT) card, 1px ink border, drop shadow — mounted once, overlaying the whole page, repositioned every frame:
- Position: on every pointermove over the page root, record the pointer's position relative to the root element. Each frame, lerp a "current position" 18% of the way toward that raw target (PREVIEW_POS_LERP = 0.18). Offset the lerped position by (+32px, -200px) (PREVIEW_OFFSET_X / PREVIEW_OFFSET_Y) so the card floats above-right of the cursor rather than under it, then clamp both axes to stay at least 16px (PREVIEW_MARGIN) inside the root's bounds. Write the result as 'transform: translate(px, py) rotate(tiltDeg)' on the outer wrapper element every frame — this element is never touched by GSAP.
- Tilt: track the pointer's raw per-frame horizontal delta (current target x minus previous frame's target x). Divide by 40 (PREVIEW_TILT_VELOCITY_DIVISOR) and clamp to ±9° (PREVIEW_TILT_MAX) to get a target tilt; ease the actual tilt 15% of the way toward it each frame (PREVIEW_TILT_LERP), so fast cursor moves visibly tilt the card like it has weight, and it settles flat when the cursor is still.
- Enter/exit: opacity and scale live on a separate *inner* element (never the position/rotation wrapper) so GSAP's transform never conflicts with the per-frame position write. On row pointerenter, kill any running tween and animate the inner element from its current state to opacity 1 / scale 1 over 0.5s (PREVIEW_ENTER_DURATION) with ease "back.out(1.6)" (starting scale is 0.82, PREVIEW_ENTER_SCALE_FROM, when idle). On row pointerleave, animate to opacity 0 / scale 0.7 (PREVIEW_EXIT_SCALE_TO) over 0.4s (PREVIEW_EXIT_DURATION) with ease "power2.in" — the card visibly shrinks and vanishes rather than just fading.
- Content: on every row pointerenter, swap a single '<img>' element's 'src' to that row's local photograph ('object-fit: cover', filling the card above a monospace caption bar) and its 'alt' to the project name — no redraw needed, it's a fixed photograph. Preload all six on mount ('new Image(); img.src = path') so the first hover is instant. The same four accent corner ticks are overlaid on the photograph's container, echoing the DOM ticks elsewhere. The caption bar below shows the photograph's label and project name (e.g. "Stair core, plan view — Vane House").
- Below 860px, hide the preview entirely (touch devices have no persistent hover) and keep the plain index list.

## Imagery
Six local WebP photographs (public/img/demos/peek-list/01.webp … 06.webp, each under 300KB), one per index row in order. Generate each with an AI image tool; every prompt below ends with the same constraint — no readable text, logos, watermarks or signage anywhere in frame, no people:
1. Monolithic board-formed concrete building at dusk; sharp angular volume, one deep-set glazed entrance; low golden-hour sun raking the concrete grain; empty concrete forecourt foreground; distant tree line; pale blue sky; 35mm lens.
2. Open timber post-and-beam pavilion in a wild meadow, golden hour; exposed wooden rafters and columns; a simple wooden table under the roof; tall grass foreground; mature trees behind; warm natural light.
3. Museum-like interior atrium; long glass coffered skylight overhead; pale limestone walls; a straight staircase with a slim steel rail; polished stone floor reflecting light; potted trees near a glass stair core; soft daylight.
4. Straight-down view into a sculptural spiral staircase; pale terrazzo treads; a smooth curved concrete balustrade; a slim steel handrail following the curve; an oval void at center revealing the floor below; soft even daylight.
5. Minimalist courtyard with a still reflecting pool; board-formed concrete walls; a large upright standing stone by the water; ornamental grasses and ferns at the pool edge; a timber deck path; warm interior light through a glazed door at dusk; overcast sky.
6. Detailed cross-section architectural study model, pale wood and museum board; multiple floors of a house sliced open revealing interior stairs and rooms; on a plain grey plinth against a neutral grey backdrop; soft studio lighting.

## Section 3: Practice
Eyebrow "The Practice", H2 "We draw before we decide." Two paragraphs about keeping every project in-house from survey to snag list, and never rendering a view before it exists as a section drawing. A pull-quote with a 2px accent left border: "A plan is just a promise until the section proves it stands up."

## Section 4: Process
Eyebrow "How a Building Gets Made", H2 "Four stages, one drawing set." A 2-column grid (1px hairline gaps forming a ruled table, collapsing to 1 column under 860px) of four plate-style cards — each with its own four corner ticks — titled Survey, Massing, Detail, Document, with a one-sentence description of that stage.

## Section 5: Footer
Serif H2 (clamp(2rem, 5vw, 3.2rem)) "Commission a building.", supporting copy about a two-week first massing study, a pill CTA "Start a Project →" (ink background, turns accent lime with ink text on hover, opens the local planning dialog), and a bottom row (1px top hairline) with "© 2026 PLINTH Architecture Studio" and the same email.

## Scroll animations
Every reveal on the page — eyebrows, headings, paragraphs, index rows, process cards, footer elements — uses one "frame reveal" instead of a generic fade-up: set 'opacity: 0' and 'clip-path: inset(42% 42% 42% 42%)' (FRAME_REVEAL_INSET), then on ScrollTrigger onEnter (trigger = element, start "top 85%", toggleActions "play none none reverse") animate to 'opacity: 1' / 'clip-path: inset(0% 0% 0% 0%)' over 0.8s (FRAME_REVEAL_DURATION) ease "power3.out" — a drafting viewport opening around the content, never a plain slide or fade. onLeaveBack reverses over 0.35s ease "power2.in". Index rows and process cards stagger 0.09s per item (FRAME_REVEAL_STAGGER). No plain translateY+opacity fade anywhere, and no numbered "01/02/03" list styling. Row hover indent/invert and the cursor-following preview are the only other motion.

## Performance & accessibility
Preload the six local photographs on mount so hover never shows an empty frame; swapping the preview's 'src' is the only per-hover cost, since the per-frame follow loop is limited to two lerped numbers and one 'transform' write on the wrapper (image swap and transform write never touch the same element/property). Pause the follow loop via an IntersectionObserver on the page root when off-screen, resume on re-entry. Use a ResizeObserver on the page root (not window) to keep the preview's clamp bounds in sync. Respect prefers-reduced-motion: disable the hero scanline and cue-arrow bounce, zero the velocity tilt, shorten the preview's enter animation to 0.15s, and set every frame-reveal to its resting state instantly. Nav links, row hit targets and CTAs are real interactive elements with visible hover states and sufficient contrast (#15140F on #FAFAF8, paper-on-ink when active). The preview card, its ticks, and the scanline are aria-hidden with an empty 'alt' on the decorative image; the index stays fully readable as plain text with or without hover support.

## 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": "peek-list",
  "brand": "PLINTH",
  "accent": "#6a5947",
  "title": "Begin with the place",
  "intro": "Record the site, the people and the intended use before deciding on a building.",
  "facts": [
    [
      "Starting point",
      "Choose a focus, describe the audience and keep a scope brief."
    ],
    [
      "Review",
      "Scope, supplied material, timing and the intended use."
    ],
    [
      "Handover to discuss",
      "A concept drawing set and a schedule of surveys and decisions needed next."
    ]
  ],
  "groups": [
    {
      "label": "Project focus",
      "options": [
        {
          "title": "New place",
          "detail": "A site and programme study, massing options and a scope for the next design stage."
        },
        {
          "title": "Existing building",
          "detail": "An initial brief for adaptation, with current conditions and survey needs recorded."
        }
      ]
    }
  ],
  "brief": "Describe the audience, the intended result, the material you already have and any timing constraints.",
  "notes": [
    "This is a local project brief. Scope, availability and any fee would be agreed in a separate conversation."
  ]
}

- 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.