# Presentation Scene Composition Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Recompose presentation Scenes 3, 4, and 5 so they use the 720p stage, and lightly tune Scene 10 graph/interrupt readability.
**Architecture:** Keep the existing storyboard, route, reducer, and demo state intact. Rewrite only the scene renderers inside `SceneBody.tsx` and tune CSS in the existing presentation stylesheets. Scene 10 remains the same data flow; this slice changes hierarchy and readability, not demo behavior.
**Tech Stack:** React, TypeScript, Vitest, Testing Library, CSS, existing Motion wrappers, existing Vite presentation route.
## Global Constraints
- Follow design spec: `docs/superpowers/specs/2026-07-08-presentation-scene-composition-design.md`.
- Do not introduce a generic diagram framework in this slice.
- Do not replace the chat UI, Q&A panel, evidence inspector, storyboard catalog, or recursive architecture figure.
- Do not add demo RPC calls, recording events, or new runtime state.
- Preserve existing keyboard/hash navigation behavior.
- Screenshot smoke output belongs under `web/apps/console/.visual-smoke/`, which is ignored.
- Do not commit `.superpowers/` local progress files.
---
## File Structure
- Modify: `web/apps/console/src/presentation/SceneBody.tsx`
- Owns Scene 3, Scene 4, and Scene 5 markup.
- Modify: `web/apps/console/src/presentation/SceneBody.test.tsx`
- Adds structural tests for the recomposed scenes.
- Modify: `web/apps/console/src/presentation/presentation.css`
- Replaces the small-card scene CSS for positioning, boundary, and lifecycle.
- Modify: `web/apps/console/src/presentation/styles/demo-workflow.css`
- Tunes Scene 10 graph/contract readability and proportions.
- Modify: `web/apps/console/src/presentation/DemoWorkflowScene.test.tsx`
- Pins approval-contract readability without changing demo behavior.
- Modify: `docs/current_roadmap.md`
- Marks the composition pass complete after verification.
- Move: `docs/superpowers/plans/2026-07-08-presentation-scene-composition.md`
- To `docs/historical/superpowers/plans/2026-07-08-presentation-scene-composition.md` after implementation.
---
### Task 1: Recompose Scene 3 Positioning Map
**Files:**
- Modify: `web/apps/console/src/presentation/SceneBody.tsx`
- Modify: `web/apps/console/src/presentation/SceneBody.test.tsx`
- Modify: `web/apps/console/src/presentation/presentation.css`
**Interfaces:**
- Consumes: `SceneDefinition`, `SceneBeatDefinition`, `DiscussionLinks`, existing `StageCaption`.
- Produces: a `PositioningScene` that renders `aria-label="positioning map"` and marks the center substrate with `data-positioning-active="true"` on `lda-position`.
- [ ] **Step 1: Write failing tests for the positioning map**
Add these tests inside `describe("SceneBody", () => { ... })` in `SceneBody.test.tsx`:
```tsx
it("renders Scene 3 as a full positioning map", () => {
const location: PresentationLocation = { kind: "main", sceneId: "positioning", beatId: "landscape", focusPath: [] };
render(
{beat.caption}
Direct action
Typed workflow substrate for external agents and human operators.
Adjacent systems
{scene.evidencePointer}
> ); }; ``` - [ ] **Step 4: Replace positioning CSS** In `presentation.css`, replace the existing `.scene-body__positioning-grid`, `.scene-body__positioning-card`, and `.scene-body__positioning-card--active` rules with: ```css .scene-body__positioning-map { display: grid; grid-template-columns: minmax(13rem, 0.9fr) minmax(20rem, 1.35fr) minmax(13rem, 0.9fr); gap: 1rem; align-items: stretch; margin-top: 1.1rem; min-height: 20rem; } .scene-body__positioning-column { display: grid; align-content: start; gap: 0.7rem; } .scene-body__positioning-label { margin: 0; color: var(--color-editorial-muted, oklch(0.48 0.025 65)); font: 700 0.68rem/1 var(--font-mono, monospace); letter-spacing: 0.08em; text-transform: uppercase; } .scene-body__positioning-tile, .scene-body__positioning-substrate { border: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 30%, transparent); border-radius: 0.85rem; background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 78%, white); color: var(--color-editorial-ink, oklch(0.19 0.015 65)); } .scene-body__positioning-tile { min-height: 5.8rem; padding: 0.85rem; } .scene-body__positioning-tile strong { display: block; margin-bottom: 0.35rem; color: var(--color-editorial-ink, oklch(0.19 0.015 65)); } .scene-body__positioning-tile span { color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 72%, var(--color-editorial-muted, oklch(0.48 0.025 65))); font-size: 0.82rem; line-height: 1.35; } .scene-body__positioning-substrate { display: grid; align-content: center; gap: 0.8rem; padding: 1.15rem; box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--accent-cyan, oklch(0.7 0.16 195)) 18%, transparent); } .scene-body__positioning-substrate strong { color: var(--color-editorial-ink, oklch(0.19 0.015 65)); font-size: 2rem; line-height: 0.95; } .scene-body__positioning-substrate p { max-width: 28ch; margin: 0; color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 82%, var(--color-editorial-muted, oklch(0.48 0.025 65))); } .scene-body__positioning-substrate ul { display: flex; flex-wrap: wrap; gap: 0.45rem; margin: 0; padding: 0; list-style: none; } .scene-body__positioning-substrate li { border: 1px solid color-mix(in oklch, var(--accent-cyan, oklch(0.7 0.16 195)) 42%, transparent); border-radius: 999px; padding: 0.25rem 0.5rem; color: var(--color-editorial-ink, oklch(0.19 0.015 65)); font-size: 0.72rem; font-weight: 700; } .scene-body__positioning-map[data-positioning-active-region="lda"] .scene-body__positioning-tile { opacity: 0.58; } .scene-body__positioning-substrate[data-positioning-active="true"] { transform: translateY(-0.25rem); border-color: color-mix(in oklch, var(--accent-cyan, oklch(0.7 0.16 195)) 68%, transparent); background: color-mix(in oklch, var(--accent-cyan, oklch(0.7 0.16 195)) 8%, var(--color-editorial-paper, oklch(0.975 0.012 82))); } ``` - [ ] **Step 5: Run tests and commit Task 1** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/SceneBody.test.tsx pnpm --dir web --filter @lda/console typecheck ``` Expected: PASS. Commit: ```powershell git add web/apps/console/src/presentation/SceneBody.tsx web/apps/console/src/presentation/SceneBody.test.tsx web/apps/console/src/presentation/presentation.css git commit -m "feat: recompose positioning scene" ``` --- ### Task 2: Recompose Scene 4 Planner Runtime Boundary **Files:** - Modify: `web/apps/console/src/presentation/SceneBody.tsx` - Modify: `web/apps/console/src/presentation/SceneBody.test.tsx` - Modify: `web/apps/console/src/presentation/presentation.css` **Interfaces:** - Consumes: `BoundaryScene` beat IDs `planner`, `runtime`, and `boundary`. - Produces: a boundary region with `aria-label="planner runtime boundary"` and `data-boundary-active`. - [ ] **Step 1: Write failing boundary tests** Add these tests to `SceneBody.test.tsx`: ```tsx it("renders Scene 4 as a planner runtime boundary", () => { const location: PresentationLocation = { kind: "main", sceneId: "planner-runtime", beatId: "boundary", focusPath: [] }; render({beat.caption}
{scene.evidencePointer}
> ); }; ``` - [ ] **Step 4: Replace boundary CSS** In `presentation.css`, replace `.scene-body__boundary`, `.scene-body__boundary-side`, `.scene-body__boundary-divider`, and related dim rules with: ```css .scene-body__boundary { display: grid; grid-template-columns: minmax(0, 1fr) minmax(8rem, 0.26fr) minmax(0, 1fr); gap: 1rem; align-items: stretch; margin-top: 1.2rem; min-height: 20rem; } .scene-body__boundary-pane { display: grid; align-content: center; gap: 0.85rem; border: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 32%, transparent); border-radius: 1rem; padding: 1.1rem; background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 82%, white); color: var(--color-editorial-ink, oklch(0.19 0.015 65)); } .scene-body__boundary-pane[data-boundary-emphasis="reduced"] { opacity: 0.58; } .scene-body__boundary-pane h3 { margin: 0; color: var(--color-editorial-ink, oklch(0.19 0.015 65)); font-size: 1.8rem; line-height: 1; } .scene-body__boundary-pane > span { color: var(--color-editorial-muted, oklch(0.48 0.025 65)); font: 700 0.68rem/1 var(--font-mono, monospace); letter-spacing: 0.08em; text-transform: uppercase; } .scene-body__boundary-pane ul { display: grid; gap: 0.45rem; margin: 0; padding-left: 1rem; color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 78%, var(--color-editorial-muted, oklch(0.48 0.025 65))); } .scene-body__boundary-seam { display: grid; place-content: center; gap: 0.35rem; border-inline: 2px solid color-mix(in oklch, var(--accent-cyan, oklch(0.7 0.16 195)) 58%, transparent); color: var(--color-editorial-ink, oklch(0.19 0.015 65)); text-align: center; } .scene-body__boundary-seam strong { font-size: 0.85rem; } .scene-body__boundary-seam span { color: var(--color-editorial-muted, oklch(0.48 0.025 65)); font-size: 0.72rem; line-height: 1.25; } .scene-body__boundary[data-boundary-active="boundary"] .scene-body__boundary-seam { background: color-mix(in oklch, var(--accent-cyan, oklch(0.7 0.16 195)) 7%, transparent); } ``` - [ ] **Step 5: Run tests and commit Task 2** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/SceneBody.test.tsx pnpm --dir web --filter @lda/console typecheck ``` Expected: PASS. Commit: ```powershell git add web/apps/console/src/presentation/SceneBody.tsx web/apps/console/src/presentation/SceneBody.test.tsx web/apps/console/src/presentation/presentation.css git commit -m "feat: recompose planner runtime scene" ``` --- ### Task 3: Recompose Scene 5 Lifecycle Rail **Files:** - Modify: `web/apps/console/src/presentation/SceneBody.tsx` - Modify: `web/apps/console/src/presentation/SceneBody.test.tsx` - Modify: `web/apps/console/src/presentation/presentation.css` **Interfaces:** - Consumes: lifecycle beat IDs `draft`, `artifact`, `deployment`, and `run`. - Produces: `aria-label="workflow lifecycle rail"` and a changing current-state explanation panel. - [ ] **Step 1: Write failing lifecycle tests** Add these tests to `SceneBody.test.tsx`: ```tsx it("renders Scene 5 as a full workflow lifecycle rail", () => { const location: PresentationLocation = { kind: "main", sceneId: "lifecycle", beatId: "deployment", focusPath: [] }; render({beat.caption}
{scene.evidencePointer}
> ); }; ``` - [ ] **Step 4: Replace lifecycle CSS** In `presentation.css`, replace `.scene-body__lifecycle`, `.scene-body__lifecycle-stage`, `.scene-body__lifecycle-number`, `.scene-body__lifecycle-arrow`, and active-state lifecycle rules with: ```css .scene-body__lifecycle { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.65rem; align-items: stretch; margin-top: 1.2rem; } .scene-body__lifecycle-stage { position: relative; display: grid; align-content: start; gap: 0.5rem; min-height: 9rem; border: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 32%, transparent); border-radius: 0.9rem; padding: 0.9rem; background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 82%, white); color: var(--color-editorial-ink, oklch(0.19 0.015 65)); } .scene-body__lifecycle-stage[data-lifecycle-active="false"] { opacity: 0.68; } .scene-body__lifecycle-stage[data-lifecycle-active="true"] { opacity: 1; transform: translateY(-0.25rem); border-color: color-mix(in oklch, var(--accent-cyan, oklch(0.7 0.16 195)) 58%, transparent); background: color-mix(in oklch, var(--accent-cyan, oklch(0.7 0.16 195)) 8%, var(--color-editorial-paper, oklch(0.975 0.012 82))); } .scene-body__lifecycle-stage strong { color: var(--color-editorial-ink, oklch(0.19 0.015 65)); font-size: 1.2rem; } .scene-body__lifecycle-stage small { color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 72%, var(--color-editorial-muted, oklch(0.48 0.025 65))); line-height: 1.3; } .scene-body__lifecycle-number { display: inline-flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem; border-radius: 50%; background: color-mix(in oklch, var(--accent-cyan, oklch(0.7 0.16 195)) 74%, white); color: var(--color-editorial-ink, oklch(0.19 0.015 65)); font: 800 0.72rem/1 var(--font-mono, monospace); } .scene-body__lifecycle-arrow { position: absolute; right: -0.55rem; top: 50%; color: var(--color-editorial-muted, oklch(0.48 0.025 65)); transform: translateY(-50%); } .scene-body__lifecycle-current { display: grid; gap: 0.3rem; margin-top: 0.9rem; border: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 28%, transparent); border-radius: 0.85rem; padding: 0.8rem 0.9rem; background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 86%, white); color: var(--color-editorial-ink, oklch(0.19 0.015 65)); } .scene-body__lifecycle-current span { color: var(--color-editorial-muted, oklch(0.48 0.025 65)); font: 700 0.66rem/1 var(--font-mono, monospace); letter-spacing: 0.08em; text-transform: uppercase; } .scene-body__lifecycle-current strong, .scene-body__lifecycle-current p { margin: 0; } .scene-body__lifecycle-current p { color: color-mix(in oklch, var(--color-editorial-ink, oklch(0.19 0.015 65)) 76%, var(--color-editorial-muted, oklch(0.48 0.025 65))); } ``` Keep the existing `.scene-body__authoring-number` styles by splitting any combined selector that used `.scene-body__lifecycle-number, .scene-body__authoring-number`. After this task, `.scene-body__authoring-number` must still render the Scene 7 numbered circles. - [ ] **Step 5: Run tests and commit Task 3** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/SceneBody.test.tsx pnpm --dir web --filter @lda/console typecheck ``` Expected: PASS. Commit: ```powershell git add web/apps/console/src/presentation/SceneBody.tsx web/apps/console/src/presentation/SceneBody.test.tsx web/apps/console/src/presentation/presentation.css git commit -m "feat: recompose lifecycle scene" ``` --- ### Task 4: Tune Scene 10 Demo Graph And Interrupt Contract **Files:** - Modify: `web/apps/console/src/presentation/DemoWorkflowScene.test.tsx` - Modify: `web/apps/console/src/presentation/styles/demo-workflow.css` **Interfaces:** - Consumes: existing `DemoWorkflowScene` approval beat and `InterruptContractPreview`. - Produces: a readable graph/contract layout without changing data or component props. - [ ] **Step 1: Add an approval readability test** In `DemoWorkflowScene.test.tsx`, extend the existing `"makes the Scene 10 approval contract the primary visual"` test: ```tsx it("makes the Scene 10 approval contract the primary visual", () => { renderBeat("approval", "interrupt-evidence"); const stage = screen.getByLabelText("demo workflow stage"); expect(stage).toHaveAttribute("data-demo-layout", "approval"); expect(screen.getByLabelText("typed interrupt contract")).toHaveAttribute("data-hero", "true"); expect(screen.getByLabelText("typed interrupt contract")).toHaveTextContent("Operator decision"); expect(screen.getByLabelText("typed interrupt contract")).toHaveTextContent("Resume outcomes"); expect(screen.getByLabelText("workflow graph")).toBeInTheDocument(); }); ``` If the test already contains the first three assertions, replace it with the block above. - [ ] **Step 2: Run demo scene tests and verify they pass before CSS** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DemoWorkflowScene.test.tsx ``` Expected: PASS. This confirms the task is visual/readability only. - [ ] **Step 3: Tune demo workflow CSS** In `web/apps/console/src/presentation/styles/demo-workflow.css`, update only existing selectors. Use these target values: ```css .demo-workflow-stage[data-demo-layout="approval"] .demo-workflow-stage__graph, .demo-workflow-stage[data-demo-layout="interrupt"] .demo-workflow-stage__graph { grid-template-columns: minmax(18rem, 0.78fr) minmax(26rem, 1.22fr); align-items: stretch; } .demo-workflow-stage[data-demo-layout="approval"] .interrupt-contract-preview, .demo-workflow-stage[data-demo-layout="interrupt"] .interrupt-contract-preview { min-width: 0; color: var(--text-primary); } .demo-workflow-stage[data-demo-layout="approval"] .workflow-graph-stage, .demo-workflow-stage[data-demo-layout="interrupt"] .workflow-graph-stage { min-height: 18rem; } .presentation-route .workflow-graph-stage__node { color: var(--text-primary); } .workflow-graph-stage__node strong { color: var(--text-primary); } .workflow-graph-stage__node small, .workflow-graph-stage__node-state { color: color-mix(in oklch, var(--text-primary) 76%, var(--text-muted)); } .workflow-graph-stage__node[data-execution-state="future"] { opacity: 0.72; } .workflow-graph-stage__node[data-execution-state="completed"] { opacity: 0.9; } .interrupt-contract-preview__schema pre { max-height: 7.5rem; color: color-mix(in oklch, var(--text-primary) 82%, var(--text-muted)); } ``` Do not duplicate selectors if they already exist. Merge these values into the current blocks. - [ ] **Step 4: Run tests and commit Task 4** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/DemoWorkflowScene.test.tsx pnpm --dir web --filter @lda/console typecheck ``` Expected: PASS. Commit: ```powershell git add web/apps/console/src/presentation/DemoWorkflowScene.test.tsx web/apps/console/src/presentation/styles/demo-workflow.css git commit -m "fix: tune demo graph contract readability" ``` --- ### Task 5: Screenshot Smoke, Roadmap, And Archive **Files:** - Modify: `docs/current_roadmap.md` - Move: `docs/superpowers/plans/2026-07-08-presentation-scene-composition.md` to `docs/historical/superpowers/plans/2026-07-08-presentation-scene-composition.md` **Interfaces:** - Consumes: completed scene composition tasks. - Produces: verified screenshot set and live roadmap entry pointing to the archived plan. - [ ] **Step 1: Run focused verification** Run: ```powershell pnpm --dir web --filter @lda/console test -- src/presentation/SceneBody.test.tsx src/presentation/DemoWorkflowScene.test.tsx pnpm --dir web --filter @lda/console typecheck pnpm --dir web --filter @lda/console build ``` Expected: - SceneBody and DemoWorkflowScene tests pass. - Typecheck prints no TypeScript errors. - Build succeeds with the existing Vite chunk-size warning only. - [ ] **Step 2: Capture screenshot smoke** With `pnpm dev` running, use the existing browser smoke method used by prior presentation slices. Capture these routes at `1280x720`: ```text http://127.0.0.1:5173/present#scene/positioning/landscape http://127.0.0.1:5173/present#scene/positioning/lda-position http://127.0.0.1:5173/present#scene/planner-runtime/planner http://127.0.0.1:5173/present#scene/planner-runtime/boundary http://127.0.0.1:5173/present#scene/lifecycle/draft http://127.0.0.1:5173/present#scene/lifecycle/run http://127.0.0.1:5173/present#scene/workflow-demo/approval ``` Save screenshots under: ```text web/apps/console/.visual-smoke/ ``` Expected visual checks: - Scene 3 uses the center of the canvas and reads as a map. - Scene 4 has a clear central boundary and two large panes. - Scene 5 has a readable Draft -> Artifact -> Deployment -> Run rail. - Scene 10 graph labels and interrupt-contract labels are readable. - No stage scrollbars are visible. - [ ] **Step 3: Update roadmap** In `docs/current_roadmap.md`, update the presentation visual slices list so item 3 reads: ```markdown 3. Completed: scene composition pass expanded the positioning map, planner/runtime boundary, lifecycle rail, and Scene 10 demo graph/contract readability. Implementation: [`presentation scene composition`](historical/superpowers/plans/2026-07-08-presentation-scene-composition.md). 4. Presentation craft pass: tune motion, discussion-chip placement, Q&A modal hierarchy, evidence receipt placement, and remaining generic-slide styling after the compositions are stable. ``` - [ ] **Step 4: Archive the plan** Run: ```powershell Move-Item docs/superpowers/plans/2026-07-08-presentation-scene-composition.md docs/historical/superpowers/plans/2026-07-08-presentation-scene-composition.md ``` - [ ] **Step 5: Run docs/status checks** Run: ```powershell rg -n '2026-07-08-presentation-scene-composition' docs/current_roadmap.md docs/historical/superpowers/plans docs/superpowers/plans git status --short git diff --check ``` Expected: - `docs/current_roadmap.md` points to the historical plan path. - No active plan with this filename remains in `docs/superpowers/plans/`. - `.visual-smoke/` is ignored. - `.superpowers/` is not staged. - `git diff --check` reports no whitespace errors. - [ ] **Step 6: Commit Task 5** Commit: ```powershell git add docs/current_roadmap.md docs/historical/superpowers/plans/2026-07-08-presentation-scene-composition.md git commit -m "docs: record presentation scene composition" ``` --- ## Final Verification Run: ```powershell pnpm --dir web test pnpm --dir web typecheck pnpm --dir web build git diff --check git status --short ``` Expected: - All web tests pass, except any explicitly reported pre-existing flaky timeout must be named in the final report with the failing test. - Typecheck is clean. - Build succeeds with only the existing Vite chunk-size warning. - Whitespace check is clean. - Git status has no unintended files; `.superpowers/` and `.visual-smoke/` are not staged. ## Self-Review - Spec coverage: Tasks 1-3 cover Scenes 3, 4, and 5. Task 4 covers Scene 10. Task 5 covers screenshots, roadmap, and plan archival. - Completion-word scan: no unresolved implementation markers are present. - Type consistency: all new attributes and labels referenced by tests are produced by the matching scene renderers. - Scope check: no chat replacement, Q&A rewrite, evidence-inspector redesign, route change, or demo state change is included.