---
path: /atelier/video
surface: customer
domain: atelier
auth: signed-in
source: apps/oshun/web/src/app/atelier/video/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; refreshed
  2026-06-28 in apps/oshun/web/e2e/atelier-video-render-queue.spec.ts: route
  anchors, 12 storyboard panels, render queue, selected shot card,
  disabled-placeholder Cut action, read-only interaction contract,
  reduced-motion static state, offline-stable loaded markup, and 390 px
  no-overflow stack; refreshed 2026-06-30 in
  apps/oshun/web/e2e/atelier-motion-to-cinematheque.spec.ts for optional motion
  handoff query context and inbound panel rendering.'
---

# Atelier · XII · Cinematheque

## Purpose

Video atelier — "a short film, storyboarded." Five-step workflow: treatment →
twelve-panel storyboard → shot list → render queue → final cut. Server-rendered
by `apps/oshun/web/src/app/atelier/video/page.tsx` via `getAtelierVideo()` →
`<AtelierVideo data>`.

## Entry points

- **Atelier index** (`/atelier`) — third room card
- **Lilith index** (`/lilith`) — section VIII card 44 "XII · Cinematheque"
- **Motion handoff** (`/atelier/motion`) — "Open in Cinematheque" sends
  `/atelier/video?from=motion&shot=sh-03&take=take-02&voice=foundry-take-03&light=forms-cream-north`
  and renders the inbound motion context panel
- **Direct URL / bookmark** — yes (signed-in)

## Layout regions

`AtelierVideo` (`apps/oshun/web/src/components/lilith/atelier.tsx`) renders
inside `LWebShell` with `LCustomerNav active="explore"`.

The route root exposes `data-atelier-video-page` with
`data-atelier-video-shot-count="12"`,
`data-atelier-video-render-queue-count="3"`,
`data-atelier-video-current-shot="sh 06"`, and
`data-atelier-video-render-progress="64"`. Its body exposes
`data-atelier-video-layout`; below 980 px it stacks to one column and the 390 px
Playwright path verifies no horizontal overflow.

- **Plate head** (`LAPlateHead no="XII"`):
  - kicker: "The atelier · cinematheque"
  - title: `A short film, <em>storyboarded</em>.`
  - right chips: "04 : 38 / 06 : 00", "9 of 12 shots", "Rendering · take 02"
    (accent)
- **Three-column body** (`230px 1fr 320px`):
  - **Left rail** (`LAStepRail`, current=3): five steps — "Treatment · written",
    "Storyboard · twelve panels", "Shot list · cameras, lenses", "Render · queue
    running", "Cut · final edit"
  - **Center**:
    - **Storyboard grid** (`data-atelier-video-storyboard`): 4×3 desktop grid of
      12 16:9 panels with procedural SVG illustrations + per-panel state
      (`rendered` for sh 01–05, `rendering · 64%` for sh 06, `queued` overlay
      for sh 07–10, `drafted` overlay for sh 11–12); panel sh 06 exposes
      `data-atelier-video-shot-selected="true"` and an accent border
    - Each panel footer shows `sh NN` + time from `data.shotTimes` + the title
      from `data.shotTitles`
    - **Render queue** (`data-atelier-video-render-queue`): three rows from
      `data.renderQueue` — sh 06 (rendering, 64%, eta 02:14, accent treatment),
      sh 07 (queued, eta 04:42), sh 08 (queued, eta 06:18)
  - **Right**:
    - **Motion handoff** (conditional): when the URL includes the exact motion
      handoff query, a compact panel exposes
      `data-atelier-video-inbound-handoff`,
      `data-atelier-video-inbound-source="motion"`,
      `data-atelier-video-inbound-state="url-context"`,
      `data-atelier-video-inbound-shot="sh 03"`,
      `data-atelier-video-inbound-take="take 02"`,
      `data-atelier-video-inbound-voice="foundry · take 03"`, and
      `data-atelier-video-inbound-light="forms · cream-north"`
    - **Shot · sh 06 card** (accent border): 16:9 SVG render + `T+00:48 · 24fps`
      watermark + `LAProgress value=0.64 eta="02:14"`
    - `LField` rows: Camera "Locked, slow tilt up", Lens "35 mm · ƒ2.8", Frame
      rate "24 fps", Length "00:12", Light "North window, single source", Engine
      "Lilith Cine · v1.4", Sound "From foundry · 02:14 stem"
    - **"Open in Cut · timeline" button** (ghost, full)

## States

- [x] **Loading boundary absence** — no segment `loading.tsx` exists under
      `apps/oshun/web/src/app/atelier/video`; `getAtelierVideo()` currently
      returns the synchronous fixture through the server component
- [x] **Populated** — fixture provides 12 shot titles/times + 3 render-queue
      entries, asserted via `data-atelier-video-shot-count="12"` and
      `data-atelier-video-render-queue-count="3"`
- [x] **Mid-render** — sh 06 shows `rendering · 64%` pill, selected state, and
      shot-card progress `64`
- [x] **Queued shots** — sh 07/08/09/10 expose
      `data-atelier-video-shot-state="queued"` and queued overlays; queue rows
      sh 07 and sh 08 expose queued state + eta
- [x] **Drafted shots** — sh 11/12 expose
      `data-atelier-video-shot-state="drafted"` and drafted overlays
- [x] **Error boundary absence** — no route-local `error.tsx` exists; failures
      fall through the inherited app boundary
- [x] **Offline** — after the route is loaded, browser offline mode keeps the
      static storyboard, render queue, selected shot, and action markup visible
- [x] **Reduced motion** — progress visual is rendered as a static bar with no
      animation declared
- [x] **Mobile stack** — 390 px viewport stacks rail → storyboard/queue → shot
      card/action with no horizontal overflow
- [x] **Inbound motion handoff** — exact whitelisted query context renders the
      Motion handoff panel; bare `/atelier/video` remains the static
      Cinematheque route without inbound context

## Interactions

### Storyboard panels

- [x] **Each panel** (12, sh 01–sh 12) — read-only; tapping sh 10 does not
      select it, mutate the selected shot card, or navigate
- [x] **Highlighted panel** (sh 06, accent border) — current selection exposed
      by `data-atelier-video-shot-selected="true"`
- [x] **State pills/overlays** — read-only; rendering/queued/drafted states are
      asserted from DOM attributes and visible labels

### Render queue rows

- [x] **sh 06 row** (rendering, accent) — read-only with progress bar and
      `data-atelier-video-queue-progress="64"`
- [x] **sh 07 row** (queued, eta 04:42)
- [x] **sh 08 row** (queued, eta 06:18)

### Right column

- [x] **Motion handoff panel** — read-only URL context from `/atelier/motion`,
      with target shot, source take, inherited voice, and inherited light
- [x] **Shot card** — read-only metadata; SVG preview click does not change the
      selected shot or navigate
- [x] **"Open in Cut · timeline" button** (ghost, full) — placeholder `LBtn`
      with `aria-disabled="true"`, `data-placeholder="true"`, tooltip
      `No handler wired — placeholder`, and no navigation

## Data & contracts

- **Reads**: `getAtelierVideo()` from
  `apps/oshun/web/src/lib/lilith-data/atelier-depth.ts` — returns
  `AtelierVideoData` with `shotTimes`, `shotTitles`, `renderQueue` (planned BFF
  at `/atelier/plates/video`)
- **Optional URL context**:
  `from=motion&shot=sh-03&take=take-02&voice=foundry-take-03&light=forms-cream-north`
  maps to `AtelierMotionHandoffData` and renders the inbound panel. Other values
  are ignored.
- **Writes**: none in current static composition
- **Realtime**: render queue would update via subscription in production; none
  in current code
- **Caching**: server fetch
- **Auth/role check**: middleware enforces signed-in

## Cross-references

- Atelier index: [`atelier.md`](./atelier.md)
- Sibling rooms: [`atelier-image.md`](./atelier-image.md),
  [`atelier-audio.md`](./atelier-audio.md),
  [`atelier-forms.md`](./atelier-forms.md),
  [`atelier-motion.md`](./atelier-motion.md)
- Upstream — shot sh 06 inherits sound "From foundry · 02:14 stem"
  ([`atelier-audio.md`](./atelier-audio.md))
- Upstream — `AtelierMotion` "Compose · downstream" sends to Cinematheque
  (sh 03) with URL-scoped motion context
- Component source: `apps/oshun/web/src/components/lilith/atelier.tsx`
  (`AtelierVideo`)
- Data: `apps/oshun/web/src/lib/lilith-data/atelier-depth.ts`

## E2E coverage

Spec: `apps/oshun/web/e2e/atelier-video-render-queue.spec.ts` (4 tests)

**Coverage depth:** deep for the current static/read-only route contract:
fixture-derived storyboard rendering, coherent render queue state, selected shot
metadata, disabled-placeholder Cut action, read-only non-mutation, mobile
no-overflow, reduced-motion static state, and offline-stable loaded markup.
`apps/oshun/web/e2e/atelier-motion-to-cinematheque.spec.ts` also covers the
motion handoff URL and inbound panel. Remaining gaps are product gaps rather
than test gaps: no route-local loading/error boundaries, no live render-progress
subscription, no storyboard selection/reorder/edit flow, and no Cut timeline
target.

## Open questions / known gaps

- [x] Confirm whether the render queue auto-updates progress or is static —
      current route is static; progress remains 64% in the loaded DOM
- [ ] Document the "Open in Cut · timeline" target — is `/cut` a planned route
      or does it open a modal editor here?
- [x] Verify whether storyboard panels support drag-reordering (no affordance
      shown in code) — current panels are read-only visual cells
