V1 Web PWA · Surface walkthrough

Studio · Compose

A per-surface walkthrough of the V1 Web PWA studio surface: layout, states, interactions, data, and cross-references.

walked
8sections4 minread

On this page

Context. surface studio · domain authoring · route /studio/compose · auth anon (explicit public route) · source apps/oshun/web/src/app/studio/compose/page.tsx

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; body re-derived 2026-06-03 from current source (lane-console architecture)

Purpose#

Compose Living Scenes from kept segments and template anchors using @yemaya/living-scenes-runtime/compose-assist. The route is explicitly public (middleware adds /studio/compose to PUBLIC_PATHS); tier and tenant policy are enforced inside the route and the validation library. The page (ComposeClient) is a single client component with a 3-segment seeded timeline (breath / sky / lesson-step), drag-and-drop reorder, boundary-technique picker, scrub-preview, Compose Assist, promotion-gates panel, and audit trail.

Entry points#

  • Studio root (/studio) — promoted via the "Open Compose" quick action where present
  • Public link from marketing surfaces/studio/compose is in the middleware PUBLIC_PATHS set
  • Direct URL / bookmark — yes
  • Deep link from generation surfaces — once a kept Living Scene exists, it can route here

Layout regions#

page.tsx is a thin wrapper: export default function StudioComposePage() { return <ComposeClient /> }. The ComposeClient renders its own layout without ShellLayout:

  • Outer <main> with data-compose-ready + data-compose-surface
  • Header strip: Studio eyebrow + "Compose" h1 + tier state (data-compose-tier-state with data-compose-allowed and data-compose-routes-to-studio-editor attrs)
  • Workspace grid (data-compose-workspace): two columns on lg
    • Left column:
      • Segment library (data-segment-library): three demo segments (seg-breath, seg-sky, seg-lesson) as cards
      • Timeline (data-compose-timeline): ordered list of segments with grip handle, move-up / move-down / alternatives buttons, drag-and-drop reorder, boundary-technique select per segment
      • Alternatives panel (data-alternatives-panel) — appears when a segment is long-pressed or context-menu'd
    • Right column (aside):
      • Scrub preview (data-scrub-preview) — range input drives which segment renders in the preview pane
      • Compose Assist (data-compose-assist) — "Accept suggestion" button appends a new seg-assist-N segment with match-action technique
      • Promotion gates (data-score-promotion) — continuity pre-score, workflow policy state, reduced-motion technique map, blocked message
      • Audit trail (data-manual-override-log) — ordered list of moves, technique changes, cites

States#

  • Loading — server-rendered + client hydration; data-compose-ready flips to "true" after mount
  • Initial seeded composition — three segments rendered in default order; promotion gates show ✓ allowed (default fixtures pass)
  • Reorder via move-up / move-down — clicking arrows reorders segments; audit log appends a "Moved … to position N" entry
  • Reorder via drag-and-drop — drag a segment over another and drop; audit log appends "Drag-arranged Segment N to position M"
  • Boundary technique change — selecting from the per-segment select updates technique; audit log entry " boundary set to
  • Alternatives via right-click / long-press — alternatives panel shows first 4 technique options; clicking applies + dismisses panel
  • Compose Assist accept — appends seg-assist-1 (then -2, …) with match-action technique; audit log entry " inserted from Compose Assist with Match action"
  • Scrub preview — moving the range updates which segment narration renders inside the preview card
  • Promotion blocked — when promoteCompositionDraft throws (e.g., bad policy combo), the promotion panel shows Blocked + error message
  • Standalone PWA — usable
  • Reduced motion — verify any animation paths honor preference

Interactions#

Header tier state#

  • Tier badge — read-only display of <tier> · <segmentCount> Segments · <durationSeconds>s; data-compose-allowed mirrors validation.allowed

Segment library cards#

  • Per-segment card — read-only summary; data-segment-source, data-rights-tags attributes for diagnostic walkthroughs

Timeline rows (per segment)#

  • Move up (button aria-label="Move <segmentId> up", data-move-segment="up")
    • Disabled when: index === 0
  • Move down (button aria-label="Move <segmentId> down", data-move-segment="down")
    • Disabled when: last segment
  • Alternatives (button aria-label="Show alternatives for <segmentId>", data-technique-alternatives-toggle)
  • Boundary technique select (data-technique-picker=<segmentId>)
  • Drag handle (grip icon; draggable on <li>) — drag + drop reorder

Alternatives panel#

  • Per-option button (data-alternative-option=<techniqueId>) — applies technique and closes panel

Scrub preview#

  • Scrub range (type="range", 0-100) — updates scrub state and drives which segment narrates

Compose Assist#

  • "Accept suggestion" (button data-compose-assist-accept)
    • Function: appends a new assist segment with match-action technique
    • Telemetry: implicit via audit log only

Promotion gates#

  • Continuity pre-score / Workflow policy / Reduced motion — read-only
  • Blocked message — error string from promoteCompositionDraft

Audit trail#

  • Ordered list — newest entry at the end

Data & contracts#

  • Reads: in-page seeded INITIAL_SEGMENTS, ALL_TECHNIQUE_SUGGESTIONS, createDraft
  • Writes: none — all mutations are local React state
  • Validation library: @yemaya/living-scenes-runtime/compose-assistvalidateCompositionDraft, promoteCompositionDraft, filterComposeAssistTechniqueSuggestions
  • Realtime: none
  • Auth/role check: middleware allows anonymous (PUBLIC_PATHS); tier + tenant policy enforced inside the validator

Cross-references#

Open questions / known gaps#

  • Confirm whether anonymous access truly survives in production or whether the public route is staged behind a feature flag
  • Document where the validator obtains the real tier / tenant policy from at request time (currently all values are seeded)