From df8ab8d1745979797a0255f80f30f4fae2dfffb7 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Fri, 30 Oct 2026 00:15:33 +0100 Subject: [PATCH] feat(mockups): slot 13 curtain call; allow three.js in 13 Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 4 +- docs/DECISIONS.md | 5 ++ docs/PERMISSIONS.md | 2 +- docs/design/002-direction-round-notes.md | 14 +++++ .../13-curtain-call-brief.md | 60 +++++++++++++++++++ src/index.html | 1 + src/mockups/13-curtain-call/index.html | 15 +++++ src/mockups/13-curtain-call/main.ts | 3 + src/mockups/13-curtain-call/style.css | 1 + src/mockups/registry.ts | 3 + src/server.ts | 3 + tests/server.test.ts | 2 +- 12 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 docs/design/002-sea-chart-spikes/13-curtain-call-brief.md create mode 100644 src/mockups/13-curtain-call/index.html create mode 100644 src/mockups/13-curtain-call/main.ts create mode 100644 src/mockups/13-curtain-call/style.css diff --git a/AGENTS.md b/AGENTS.md index 5d0a879..8ba40ee 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,7 @@ # EPIC: The Musical Timeline Unofficial fan site: an interactive timeline of *EPIC: The Musical* songs. Currently 7 design-direction -mockups. Bun 1.3.14 (server, bundler, test runner), TypeScript, three.js (mockups 06/07 only), Docker. +mockups. Bun 1.3.14 (server, bundler, test runner), TypeScript, three.js (mockups 06/07/13 only), Docker. `AGENTS.md` is the single source of truth for agents here. `CLAUDE.md` and `GEMINI.md` only point here. Deeper context on demand: `docs/ARCHITECTURE.md`, `docs/DECISIONS.md`, `docs/TODO.md`. @@ -10,7 +10,7 @@ Deeper context on demand: `docs/ARCHITECTURE.md`, `docs/DECISIONS.md`, `docs/TOD Install: `bun install --frozen-lockfile` Dev: `bun run dev` (`PORT` env, default 3000) -Test: `bun test` | Single file: `bun test tests/data.test.ts` | Single case: `bun test -t "registry has 12"` +Test: `bun test` | Single file: `bun test tests/data.test.ts` | Single case: `bun test -t "registry has 13"` Typecheck: `bun run typecheck` Build: `bun run build` | Run the build: `bun run start` Docker: `docker build -t epic-timeline .` then `docker run --rm -p 3000:3000 epic-timeline` diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index b28eae0..81fad1e 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -48,3 +48,8 @@ merge request. Both override the superpowers default paths. the repo every session — measurably slower and more tokens). **Consequences:** Rule changes happen in one file; pointer files must stay thin. Plans are working artefacts: kept after merge they go stale and contradict the code, so the spec is the record. + +## 2026-10-30 — three.js allowed in mockup 13 + +**Decision:** mockup 13 (Curtain call) may use three.js, like 06 and 07. It mocks the frieze → 3D sea → +frieze → cave transition, which needs the 3D sea. three.js is already a dependency; nothing new is added. diff --git a/docs/PERMISSIONS.md b/docs/PERMISSIONS.md index 6c7a9da..a112f27 100644 --- a/docs/PERMISSIONS.md +++ b/docs/PERMISSIONS.md @@ -22,7 +22,7 @@ or `AGENTS.md` Commands. | `bun install --frozen-lockfile` | worked (no changes) | | `bun test` | worked — 34 pass, 0 fail, 3 files | | `bun test tests/data.test.ts` | worked — 10 pass | -| `bun test -t "registry has 12"` | worked — 1 pass | +| `bun test -t "registry has 13"` | worked — 1 pass | | `bun run typecheck` | worked (`tsc --noEmit`, exit 0) | | `bun run build` | worked — `dist/server.js` + hashed page assets | | `bun run dev` (`PORT=3113`) | worked — `/` and all mockup routes 200, no-slash form 302 | diff --git a/docs/design/002-direction-round-notes.md b/docs/design/002-direction-round-notes.md index 81ff46e..6d26546 100644 --- a/docs/design/002-direction-round-notes.md +++ b/docs/design/002-direction-round-notes.md @@ -184,6 +184,20 @@ This file exists because of that request. It gets updated after every user messa - *(Claude's proposal)* The 2D sea chart is now 12 Vellum atlas with threads. Next open questions are the look of the whole and how the frieze/3D layers attach to this chart. +### 13. A short mockup of the transition + +*(Claude's question)* The look of the whole: 1 vellum throughout, 2 two worlds (vellum chart and 3D, +terracotta frieze only at transitions; Claude's recommendation), 3 frieze-led. Offered a short +mockup of the transition. + +> "Short mockup please :)" + +- The user did not pick 1/2/3 yet, so mockup **13 Curtain call** shows the transition sequence with + the look as a toggle (1/2/3), defaulting to 2. +- Sequence: frieze (2D) → morphs into the 3D sea → ship reaches Cyclops' Island → back to the frieze + → into the cave. The vellum chart (12) appears as the map on the captain's table at sea. +- three.js is allowed in 13 (it is already a dependency; it reuses 07's sea). + ## Open questions (in priority order) 1. ~~Which sea-chart approach (08–11) reads best, or which mix?~~ 11's navigation + 10's style (§9). diff --git a/docs/design/002-sea-chart-spikes/13-curtain-call-brief.md b/docs/design/002-sea-chart-spikes/13-curtain-call-brief.md new file mode 100644 index 0000000..7a7c67f --- /dev/null +++ b/docs/design/002-sea-chart-spikes/13-curtain-call-brief.md @@ -0,0 +1,60 @@ +# 13 Curtain call — short transition mockup brief + +## Why + +The user's idea (verbatim, from `docs/design/002-direction-round-notes.md` §3): + +> "Maybe we can have the freize's look be the one that tries the different stuff together, like a +> curtain call from the first section to go over in the second, where it starts off 2d with the +> freize, then slowly morphs into the sea voytage, then when he lands on cyclops islands, it goes +> back to the freize, then into the cave?" + +The 2D chart is decided: **12 Vellum atlas with threads**. The open question is **the look of the +whole**, so the look is a toggle in this mockup: + +1. **Vellum throughout** — the frieze is redrawn as ink on vellum (an illustrated border of the chart); + the 3D sea is tinted warm, parchment-like. +2. **Two worlds** (default) — chart and 3D are vellum/naturalistic; the frieze keeps 04's terracotta + and black and appears only at transitions, like a curtain dropping between scenes. +3. **Frieze-led** — terracotta/black sets the whole tone; the 3D sea is stylised in that palette + (black-figure silhouettes, terracotta sky), and the vellum chart is one object on the table. + +Toggle: visible control "Look: 1 · 2 · 3", also `?look=1|2|3`. + +## The sequence (short — about 20–30 s total with Play) + +Five beats, each a step. Controls: Play/Pause, ← / → step, step dots with labels, `?beat=1..5`. + +1. **Frieze.** 04's frieze band: Troy figures, the horse. Caption "Troy falls". +2. **Morph to sea.** The frieze band's ground line becomes the horizon; figures flatten away / the band + unrolls and the camera tilts down into 07's 3D sea with the ship. The vellum chart (12's general + chart, small, static is fine — a simplified SVG redraw is fine) lies as the captain's-table map in a + corner with "You are here". +3. **Landfall.** The ship sails to Cyclops' Island; the island rises from the sea. +4. **Back to the frieze.** The curtain drops: the frieze band returns with Cyclops-saga figures + (Polyphemus, sheep, the ship's crew), caption "Polyphemus". +5. **Into the cave.** The frieze parts / zooms through a cave mouth into a simple 3D cave interior + (dark rock, firelight, the giant's silhouette is enough). A "Back to sea" control returns to beat 2. + +The transitions are the point. Make them smooth, honest and short (≈1–2 s each); respect +`prefers-reduced-motion` with crossfades. Content is light: a caption per beat, a song title chip +(e.g. "Survive") that opens nothing. No song detail panel needed. + +## Rules + +- Edit ONLY `src/mockups/13-curtain-call/` (stub files exist: index.html links credits; main.ts calls + `mountCredits()`; replace the stub style.css with unique content). three.js is allowed here (already a + dependency). Reuse by copying from `src/mockups/04-greek-frieze/` (figures.ts, glyphs.ts) and + `src/mockups/07-sea-voyage/` (scene.ts, route.ts) into your folder — don't import across mockup folders. +- Look at screenshots/04-*, 07-*, 12-* before designing. Credits footer fully visible in every beat. +- Build to `/tmp/claude-1000/-home-user-epic-the-musical-timeline/fb650f6d-47a0-47e4-8f6b-197d02417f3b/scratchpad/r3-13`, + serve with `cd && PORT=4113 bun server.js`. Kill only your own server. +- Screenshots 1440×900, `--use-gl=swiftshader --virtual-time-budget=6000` (WebGL headless): + `screenshots/13-curtain-call-beat{1..5}.png` at look 2, plus `-beat2-look1.png`, `-beat2-look3.png`, + `-beat4-look1.png`, `-beat4-look3.png`. If possible also capture a mid-transition frame + (`-morph.png`, e.g. `?beat=2&t=0.5` to freeze a transition at 50%). Look at every one; fix what's off. +- `bun test` and `bun run typecheck` must pass. Don't commit. Don't spawn subagents. +- If you run low on budget, stop and write a pause report (done / checklist / next step) instead. +- Report to `docs/design/002-sea-chart-spikes/13-curtain-call-report.md`: what you built, what works, + what doesn't, screenshots, and an honest paragraph comparing looks 1/2/3. Reply with status, + screenshot paths and concerns only. diff --git a/src/index.html b/src/index.html index 3ecd131..1a244db 100644 --- a/src/index.html +++ b/src/index.html @@ -25,6 +25,7 @@
  • 10

    Unrolling chart

    An editorial horizontal scroll whose ground is a long chart unrolling as you pan; motif threads trail beneath the route.

    Try this: Pan sideways and watch the ship and coastline move with you.

  • 11

    Atlas with insets

    An overview chart of the whole sea; each saga island opens an inset chart with its songs as ports.

    Try this: Open an island's inset, then a song, then zoom back out.

  • 12

    Vellum atlas

    The atlas overview and island plates of 11, drawn in the vellum portolan style of 10.

    Try this: Open Cyclops' Island, pick a theme, and switch the plate's motif style (A/B/C).

  • +
  • 13

    Curtain call

    The frieze curtain that carries you from the 2D story into the 3D sea and down into a landing.

    Try this: Press Play, or step through: frieze, sea, Cyclops' Island, frieze, cave. Switch the look (1/2/3).

  • diff --git a/src/mockups/13-curtain-call/index.html b/src/mockups/13-curtain-call/index.html new file mode 100644 index 0000000..a7d3c8d --- /dev/null +++ b/src/mockups/13-curtain-call/index.html @@ -0,0 +1,15 @@ + + + + + + Curtain call — EPIC Timeline mockup + + + + +
    +
    + + + diff --git a/src/mockups/13-curtain-call/main.ts b/src/mockups/13-curtain-call/main.ts new file mode 100644 index 0000000..88ded7e --- /dev/null +++ b/src/mockups/13-curtain-call/main.ts @@ -0,0 +1,3 @@ +import { mountCredits } from "../../shared/credits"; + +mountCredits(); diff --git a/src/mockups/13-curtain-call/style.css b/src/mockups/13-curtain-call/style.css new file mode 100644 index 0000000..dc23a71 --- /dev/null +++ b/src/mockups/13-curtain-call/style.css @@ -0,0 +1 @@ +body { margin: 0; --stub-13: 1; } diff --git a/src/mockups/registry.ts b/src/mockups/registry.ts index b04f2a7..c1b00c4 100644 --- a/src/mockups/registry.ts +++ b/src/mockups/registry.ts @@ -37,4 +37,7 @@ export const mockups: MockupInfo[] = [ { slug: "12-vellum-atlas", number: 12, name: "Vellum atlas", pitch: "The atlas overview and island plates of 11, drawn in the vellum portolan style of 10.", tryThis: "Open Cyclops' Island, pick a theme, and switch the plate's motif style (A/B/C)." }, + { slug: "13-curtain-call", number: 13, name: "Curtain call", + pitch: "The frieze curtain that carries you from the 2D story into the 3D sea and down into a landing.", + tryThis: "Press Play, or step through: frieze, sea, Cyclops' Island, frieze, cave. Switch the look (1/2/3)." }, ]; diff --git a/src/server.ts b/src/server.ts index 7912a9b..d8e7554 100644 --- a/src/server.ts +++ b/src/server.ts @@ -12,6 +12,7 @@ import m8 from "./mockups/09-chart-transit/index.html"; import m9 from "./mockups/10-chart-scroll/index.html"; import m10 from "./mockups/11-chart-atlas/index.html"; import m11 from "./mockups/12-vellum-atlas/index.html"; +import m12 from "./mockups/13-curtain-call/index.html"; export function startServer(port: number): Server { return Bun.serve({ @@ -42,6 +43,8 @@ export function startServer(port: number): Server { "/mockups/11-chart-atlas": Response.redirect("/mockups/11-chart-atlas/", 302), "/mockups/12-vellum-atlas/": m11, "/mockups/12-vellum-atlas": Response.redirect("/mockups/12-vellum-atlas/", 302), + "/mockups/13-curtain-call/": m12, + "/mockups/13-curtain-call": Response.redirect("/mockups/13-curtain-call/", 302), }, development: process.env.NODE_ENV !== "production", fetch() { diff --git a/tests/server.test.ts b/tests/server.test.ts index 6ccd252..e828589 100644 --- a/tests/server.test.ts +++ b/tests/server.test.ts @@ -8,7 +8,7 @@ let base: string; beforeAll(() => { server = startServer(0); base = `http://localhost:${server.port}`; }); afterAll(() => server.stop(true)); -test("registry has 12 mockups", () => expect(mockups).toHaveLength(12)); +test("registry has 13 mockups", () => expect(mockups).toHaveLength(13)); test("index links every mockup", async () => { const res = await fetch(base + "/");