# Presentation Opening Visuals 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:** Replace the text-heavy opening Scenes 1 and 2 with visual, icon-backed diagrams that explain the origin story: external agents can plan and call tools; the submitted work focuses on the workflow-platform/substrate layer that makes actions reusable. **Architecture:** Keep this slice inside the existing React presentation app. Add small source-owned presentation primitives for concept icons and concept rails, then use them in two focused scene components. Do not introduce shadcn/ui in this slice: shadcn copies components into the source tree and requires project-wide conventions; it should be a separate component-system/chat cleanup decision, not a one-off opening-slide dependency. **Tech Stack:** React 19, TypeScript, Vite, Tailwind 4 tokens already present in `editorial.css`, existing presentation CSS, Vitest + Testing Library, Playwright screenshot smoke. ## Global Constraints - Do not redesign Scenes 3, 4, or 5. - Do not change the thesis title text. - Do not add live LLM behavior. - Do not rework the report workflow demo. - Do not add named related-system comparisons before Scene 3. - Do not introduce `wf` CLI branding in the opening. - Use `Codex`, `Claude`, and `OpenCode` as planner examples. - Prefer source-owned reusable presentation primitives for chips, icon plaques, timeline steps, and placeholder surfaces. - Do not add shadcn/ui, lucide, Radix, assistant-ui, or AI SDK dependencies in this slice. - Use icons and shapes, not text-only lists. - Keep copy readable at 720p. - Main slide body must stay confident; the “not a new autonomous planning algorithm” sentence belongs in speaker notes/Q&A, not the main visual. --- ## File Structure - Create `web/apps/console/src/presentation/opening/ConceptPrimitives.tsx` - Owns small reusable presentation primitives: - `ConceptIcon` - `ConceptNode` - `ConceptRail` - These are source-owned placeholders aligned with future chat/product component language. - Create `web/apps/console/src/presentation/opening/ConceptPrimitives.test.tsx` - Pins accessible labels and reusable rendering behavior. - Create `web/apps/console/src/presentation/opening/OpeningThesisScene.tsx` - Owns Scene 1 title reveal and contribution focus. - Create `web/apps/console/src/presentation/opening/OpeningThesisScene.test.tsx` - Pins planner/tool/platform decomposition, known agent names, submitted substrate block, and defense question rail availability. - Create `web/apps/console/src/presentation/opening/ProblemLoopScene.tsx` - Owns Scene 2 action sequence vs reusable automation. - Create `web/apps/console/src/presentation/opening/ProblemLoopScene.test.tsx` - Pins simple verbs and excludes formal lifecycle terms. - Modify `web/apps/console/src/presentation/SceneBody.tsx` - Route `scene.id === "thesis"` to `OpeningThesisScene`. - Route `scene.id === "problem"` to `ProblemLoopScene`. - Leave other `narrative` scenes on `NarrativeScene`. - Modify `web/apps/console/src/presentation/SceneBody.test.tsx` - Add integration checks for Scene 1 and Scene 2. - Modify `web/apps/console/src/presentation/presentation.css` - Add visual styles for opening primitives and scene layouts. - Modify `docs/current_roadmap.md` - Mark the opening visual slice completed after implementation. - Move this plan to `docs/historical/superpowers/plans/` after completion. --- ### Task 1: Source-Owned Concept Primitives **Files:** - Create: `web/apps/console/src/presentation/opening/ConceptPrimitives.tsx` - Create: `web/apps/console/src/presentation/opening/ConceptPrimitives.test.tsx` - Modify: `web/apps/console/src/presentation/presentation.css` **Interfaces:** - Produces: - `type ConceptIconName = "planner" | "tool" | "platform" | "think" | "toolCall" | "observe" | "done" | "design" | "save" | "connect" | "run" | "inspect"` - `ConceptIcon(props: { name: ConceptIconName; label: string }): JSX.Element` - `ConceptNode(props: { title: string; subtitle?: string; icon: ConceptIconName; emphasis?: "normal" | "primary" | "muted"; children?: React.ReactNode }): JSX.Element` - `ConceptRail(props: { label: string; children: React.ReactNode }): JSX.Element` - Consumes: existing presentation CSS tokens from `.presentation-route`. - [ ] **Step 1: Write failing primitive tests** Create `web/apps/console/src/presentation/opening/ConceptPrimitives.test.tsx`: ```tsx import { render, screen } from "@testing-library/react"; import { describe, expect, it } from "vitest"; import { ConceptIcon, ConceptNode, ConceptRail } from "./ConceptPrimitives.js"; describe("ConceptPrimitives", () => { it("renders labelled concept icons without external icon dependencies", () => { render(); expect(screen.getByRole("img", { name: "Planner icon" })).toBeInTheDocument(); }); it("renders concept nodes with stable emphasis attributes", () => { render( Typed · Durable · Inspectable , ); const node = screen.getByRole("group", { name: /Workflow Platform/i }); expect(node).toHaveAttribute("data-concept-emphasis", "primary"); expect(node).toHaveTextContent("submitted substrate"); expect(node).toHaveTextContent("Typed · Durable · Inspectable"); }); it("renders a labelled concept rail", () => { render( , ); expect(screen.getByRole("group", { name: "Reusable automation rail" })).toBeInTheDocument(); expect(screen.getByText("Design")).toBeInTheDocument(); expect(screen.getByText("Run")).toBeInTheDocument(); }); }); ``` - [ ] **Step 2: Run primitive tests and confirm failure** Run: ```bash pnpm --dir web --filter @lda/console test -- src/presentation/opening/ConceptPrimitives.test.tsx ``` Expected: FAIL because `ConceptPrimitives.tsx` does not exist. - [ ] **Step 3: Implement concept primitives** Create `web/apps/console/src/presentation/opening/ConceptPrimitives.tsx`: ```tsx import type { ReactNode } from "react"; export type ConceptIconName = | "planner" | "tool" | "platform" | "think" | "toolCall" | "observe" | "done" | "design" | "save" | "connect" | "run" | "inspect"; type ConceptIconProps = { readonly name: ConceptIconName; readonly label: string; }; const iconPathFor = (name: ConceptIconName): string => { if (name === "planner") return "M7 11c0-3 2-5 5-5s5 2 5 5-2 5-5 5-5-2-5-5Zm5-8v3m0 10v5M4 11H1m22 0h-3M6 4l2 2m10-2-2 2M6 18l2-2m10 2-2-2"; if (name === "tool") return "M5 19h14M7 17V7l5-3 5 3v10M9 10h6M9 14h6"; if (name === "platform") return "M4 7h16v10H4zM8 17v3m8-3v3M7 20h10M8 10h8m-8 3h5"; if (name === "think") return "M8 15h8a4 4 0 0 0 0-8H9a5 5 0 0 0-1 10v3l3-3"; if (name === "toolCall") return "M6 7h12M6 12h8M6 17h12M18 12l3 3-3 3"; if (name === "observe") return "M2 12s4-6 10-6 10 6 10 6-4 6-10 6S2 12 2 12Zm10 3a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z"; if (name === "done") return "M4 12l5 5L20 6"; if (name === "design") return "M4 20l4-1 11-11-3-3L5 16l-1 4Zm10-14 3 3"; if (name === "save") return "M5 4h12l2 2v14H5zM8 4v6h8V4M8 20v-6h8v6"; if (name === "connect") return "M7 7h4v4H7zM13 13h4v4h-4zM11 9h3a3 3 0 0 1 3 3v1"; if (name === "run") return "M7 5v14l12-7z"; return "M3 11h18M5 5h14v14H5zM9 15h6"; }; export const ConceptIcon = ({ name, label }: ConceptIconProps) => ( ); type ConceptNodeProps = { readonly title: string; readonly subtitle?: string; readonly icon: ConceptIconName; readonly emphasis?: "normal" | "primary" | "muted"; readonly children?: ReactNode; }; export const ConceptNode = ({ title, subtitle, icon, emphasis = "normal", children, }: ConceptNodeProps) => (
{title} {subtitle && {subtitle}} {children &&
{children}
}
); type ConceptRailProps = { readonly label: string; readonly children: ReactNode; }; export const ConceptRail = ({ label, children }: ConceptRailProps) => (
{children}
); ``` - [ ] **Step 4: Add primitive CSS** Modify `web/apps/console/src/presentation/presentation.css` near the existing scene body styles: ```css .concept-rail { display: flex; align-items: stretch; gap: 0.7rem; min-width: 0; } .concept-node { position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 0.65rem; min-width: 0; border: 1px solid color-mix(in oklch, var(--stage-line) 72%, transparent); border-radius: 0.85rem; background: color-mix(in oklch, var(--stage-surface) 86%, transparent); padding: 0.72rem 0.82rem; color: var(--text-primary); } .concept-node[data-concept-emphasis="primary"] { border-color: var(--accent-cyan); background: color-mix(in oklch, var(--accent-cyan) 12%, var(--stage-surface)); box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent-cyan) 18%, transparent); } .concept-node[data-concept-emphasis="muted"] { opacity: 0.62; } .concept-icon { width: 2rem; height: 2rem; color: var(--accent-cyan); fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; } .concept-node__copy { display: grid; gap: 0.12rem; min-width: 0; } .concept-node__copy strong { color: var(--text-primary); font: 750 0.96rem/1.05 var(--font-interface); } .concept-node__copy span { color: var(--text-secondary); font: 0.78rem/1.25 var(--font-interface); } .concept-node__meta { color: var(--accent-cyan); font: 700 0.72rem/1.2 var(--font-evidence); } ``` - [ ] **Step 5: Run primitive tests** Run: ```bash pnpm --dir web --filter @lda/console test -- src/presentation/opening/ConceptPrimitives.test.tsx ``` Expected: PASS. - [ ] **Step 6: Commit** ```bash git add web/apps/console/src/presentation/opening/ConceptPrimitives.tsx web/apps/console/src/presentation/opening/ConceptPrimitives.test.tsx web/apps/console/src/presentation/presentation.css git commit -m "feat: add presentation concept primitives" ``` --- ### Task 2: Scene 1 Opening Thesis Visual **Files:** - Create: `web/apps/console/src/presentation/opening/OpeningThesisScene.tsx` - Create: `web/apps/console/src/presentation/opening/OpeningThesisScene.test.tsx` - 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: - `ConceptNode`, `ConceptRail` from `./opening/ConceptPrimitives.js` - `StageCaption` - `DiscussionLinks` remains internal in `SceneBody`; this scene does not own the Q&A rail. - Produces: - `OpeningThesisScene(props: { scene: SceneDefinition; beat: SceneBeatDefinition }): JSX.Element` - [ ] **Step 1: Write failing component test** Create `web/apps/console/src/presentation/opening/OpeningThesisScene.test.tsx`: ```tsx import { render, screen } from "@testing-library/react"; import { describe, expect, it } from "vitest"; import { findBeat, findScene } from "../storyboard.js"; import { OpeningThesisScene } from "./OpeningThesisScene.js"; const thesisScene = findScene("thesis")!; describe("OpeningThesisScene", () => { it("renders the title reveal with latent component icons", () => { render(); expect(screen.getByRole("heading", { name: /Design and Implementation of lda\.chat/i })).toBeInTheDocument(); expect(screen.getByText("Planner")).toBeInTheDocument(); expect(screen.getByText("Tool Surface")).toBeInTheDocument(); expect(screen.getByText("Workflow Platform")).toBeInTheDocument(); expect(screen.getByRole("img", { name: /Planner icon/i })).toBeInTheDocument(); expect(screen.getByRole("img", { name: /Tool Surface icon/i })).toBeInTheDocument(); expect(screen.getByRole("img", { name: /Workflow Platform icon/i })).toBeInTheDocument(); }); it("renders contribution focus without relying on lda.chat as category label", () => { render(); expect(screen.getByText("Codex / Claude / OpenCode")).toBeInTheDocument(); expect(screen.getByText("CLI / MCP / APIs")).toBeInTheDocument(); expect(screen.getByText("submitted substrate")).toBeInTheDocument(); expect(screen.getByText("Typed · Durable · Inspectable")).toBeInTheDocument(); expect(screen.queryByText("wf")).not.toBeInTheDocument(); }); }); ``` - [ ] **Step 2: Run component test and confirm failure** Run: ```bash pnpm --dir web --filter @lda/console test -- src/presentation/opening/OpeningThesisScene.test.tsx ``` Expected: FAIL because `OpeningThesisScene.tsx` does not exist. - [ ] **Step 3: Implement opening thesis scene** Create `web/apps/console/src/presentation/opening/OpeningThesisScene.tsx`: ```tsx import { StageCaption } from "../StageCaption.js"; import type { SceneBeatDefinition, SceneDefinition } from "../storyboard.js"; import { ConceptNode, ConceptRail } from "./ConceptPrimitives.js"; type OpeningThesisSceneProps = { readonly scene: SceneDefinition; readonly beat: SceneBeatDefinition; }; const title = "Design and Implementation of lda.chat"; export const OpeningThesisScene = ({ scene, beat }: OpeningThesisSceneProps) => { const contributionBeat = beat.id === "substrate"; return ( <>

{beat.caption}

AI agent for workspace workflows {contributionBeat ? "Decomposed" : scene.title}
Typed · Durable · Inspectable

{scene.evidencePointer}

); }; ``` - [ ] **Step 4: Add opening thesis CSS** Append to `web/apps/console/src/presentation/presentation.css` near other scene styles: ```css .opening-thesis { flex: 1 1 auto; min-height: 0; display: grid; grid-template-rows: minmax(8rem, 0.85fr) auto; gap: 1rem; align-items: center; } .opening-thesis__title-card { display: grid; place-items: center; gap: 0.5rem; min-height: 10rem; border: 1px solid color-mix(in oklch, var(--stage-line) 54%, transparent); border-radius: 1rem; background: radial-gradient(circle at 30% 30%, color-mix(in oklch, var(--accent-cyan) 12%, transparent), transparent 34%), var(--stage-inset); text-align: center; } .opening-thesis__title-card span { color: var(--text-secondary); font: 700 0.85rem/1 var(--font-evidence); letter-spacing: 0.08em; text-transform: uppercase; } .opening-thesis__title-card strong { max-width: 14ch; color: var(--text-primary); font: 800 clamp(2rem, 7vw, 4.8rem)/0.92 var(--font-editorial); text-wrap: balance; } .opening-thesis .concept-rail { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); } ``` - [ ] **Step 5: Wire SceneBody to Scene 1** Modify `web/apps/console/src/presentation/SceneBody.tsx` imports: ```tsx import { OpeningThesisScene } from "./opening/OpeningThesisScene.js"; ``` Modify the `case "narrative":` branch: ```tsx case "narrative": if (scene.id === "thesis") return ; return ; ``` - [ ] **Step 6: Add SceneBody integration test for Scene 1** Modify `web/apps/console/src/presentation/SceneBody.test.tsx` inside `describe("SceneBody", ...)`: ```tsx it("renders Scene 1 as an opening decomposition visual", () => { const location: PresentationLocation = { kind: "main", sceneId: "thesis", beatId: "substrate", focusPath: [] }; render( , ); expect(screen.getByLabelText("AI agent decomposition")).toBeInTheDocument(); expect(screen.getByText("submitted substrate")).toBeInTheDocument(); expect(screen.getByText("Typed · Durable · Inspectable")).toBeInTheDocument(); expect(screen.getByRole("button", { name: /where is the ai agent/i })).toBeInTheDocument(); }); ``` - [ ] **Step 7: Run tests** Run: ```bash pnpm --dir web --filter @lda/console test -- src/presentation/opening/OpeningThesisScene.test.tsx src/presentation/SceneBody.test.tsx ``` Expected: PASS. - [ ] **Step 8: Commit** ```bash git add web/apps/console/src/presentation/opening/OpeningThesisScene.tsx web/apps/console/src/presentation/opening/OpeningThesisScene.test.tsx 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: add presentation opening thesis visual" ``` --- ### Task 3: Scene 2 Action Sequence Versus Reusable Automation **Files:** - Create: `web/apps/console/src/presentation/opening/ProblemLoopScene.tsx` - Create: `web/apps/console/src/presentation/opening/ProblemLoopScene.test.tsx` - 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: - `ConceptNode`, `ConceptRail` from `./opening/ConceptPrimitives.js` - `StageCaption` - Produces: - `ProblemLoopScene(props: { scene: SceneDefinition; beat: SceneBeatDefinition }): JSX.Element` - [ ] **Step 1: Write failing component test** Create `web/apps/console/src/presentation/opening/ProblemLoopScene.test.tsx`: ```tsx import { render, screen, within } from "@testing-library/react"; import { describe, expect, it } from "vitest"; import { findBeat, findScene } from "../storyboard.js"; import { ProblemLoopScene } from "./ProblemLoopScene.js"; const problemScene = findScene("problem")!; describe("ProblemLoopScene", () => { it("renders the action sequence as useful but insufficient", () => { render(); const action = screen.getByRole("group", { name: "Action sequence" }); expect(within(action).getByText("think")).toBeInTheDocument(); expect(within(action).getAllByText("tool")).toHaveLength(2); expect(within(action).getByText("observe")).toBeInTheDocument(); expect(within(action).getByText("done")).toBeInTheDocument(); expect(screen.getByText(/useful once/i)).toBeInTheDocument(); }); it("renders reusable automation with simple verbs only", () => { render(); const automation = screen.getByRole("group", { name: "Reusable automation" }); for (const label of ["design", "save", "connect", "run", "inspect"]) { expect(within(automation).getByText(label)).toBeInTheDocument(); } for (const formalName of ["Draft", "Artifact", "Deployment", "Trace"]) { expect(screen.queryByText(formalName)).not.toBeInTheDocument(); } }); }); ``` - [ ] **Step 2: Run component test and confirm failure** Run: ```bash pnpm --dir web --filter @lda/console test -- src/presentation/opening/ProblemLoopScene.test.tsx ``` Expected: FAIL because `ProblemLoopScene.tsx` does not exist. - [ ] **Step 3: Implement problem loop scene** Create `web/apps/console/src/presentation/opening/ProblemLoopScene.tsx`: ```tsx import { StageCaption } from "../StageCaption.js"; import type { SceneBeatDefinition, SceneDefinition } from "../storyboard.js"; import { ConceptNode, ConceptRail } from "./ConceptPrimitives.js"; type ProblemLoopSceneProps = { readonly scene: SceneDefinition; readonly beat: SceneBeatDefinition; }; export const ProblemLoopScene = ({ scene, beat }: ProblemLoopSceneProps) => { const automationBeat = beat.id === "missing-contracts"; return ( <>

{beat.caption}

Action sequence

Useful once. Hard to reuse.

Reusable automation

The platform makes work reusable.

{scene.evidencePointer}

); }; ``` - [ ] **Step 4: Add problem loop CSS** Append to `web/apps/console/src/presentation/presentation.css` after the opening thesis CSS: ```css .problem-loop-scene { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 1rem; } .problem-loop-scene__side { display: grid; gap: 0.8rem; min-width: 0; border: 1px solid color-mix(in oklch, var(--stage-line) 60%, transparent); border-radius: 1rem; background: var(--stage-inset); padding: 1rem; } .problem-loop-scene__side[data-problem-active="false"] { opacity: 0.62; } .problem-loop-scene__side h2 { margin: 0; color: var(--text-primary); font: 800 clamp(1.5rem, 3vw, 2.4rem)/0.95 var(--font-editorial); } .problem-loop-scene__side p { margin: 0; color: var(--text-secondary); font: 0.95rem/1.35 var(--font-interface); } .problem-loop-scene .concept-rail { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); } .problem-loop-scene .concept-node { grid-template-columns: 1fr; justify-items: center; text-align: center; padding: 0.7rem 0.45rem; } .problem-loop-scene .concept-node__copy span, .problem-loop-scene .concept-node__meta { display: none; } .problem-loop-scene__bridge { color: var(--accent-cyan); font: 800 2rem/1 var(--font-interface); } @container presentation-canvas (max-width: 1050px) { .problem-loop-scene { grid-template-columns: 1fr; } .problem-loop-scene__bridge { display: none; } } ``` - [ ] **Step 5: Wire SceneBody to Scene 2** Modify `web/apps/console/src/presentation/SceneBody.tsx` imports: ```tsx import { ProblemLoopScene } from "./opening/ProblemLoopScene.js"; ``` Modify the `case "narrative":` branch from Task 2: ```tsx case "narrative": if (scene.id === "thesis") return ; if (scene.id === "problem") return ; return ; ``` - [ ] **Step 6: Add SceneBody integration test for Scene 2** Modify `web/apps/console/src/presentation/SceneBody.test.tsx`: ```tsx it("renders Scene 2 as action sequence versus reusable automation", () => { const location: PresentationLocation = { kind: "main", sceneId: "problem", beatId: "missing-contracts", focusPath: [] }; render( , ); expect(screen.getByLabelText("action sequence versus reusable automation")).toBeInTheDocument(); expect(screen.getByRole("group", { name: "Action sequence" })).toBeInTheDocument(); expect(screen.getByRole("group", { name: "Reusable automation" })).toBeInTheDocument(); expect(screen.queryByText("Draft")).not.toBeInTheDocument(); expect(screen.queryByText("Artifact")).not.toBeInTheDocument(); expect(screen.queryByText("Deployment")).not.toBeInTheDocument(); }); ``` - [ ] **Step 7: Run tests** Run: ```bash pnpm --dir web --filter @lda/console test -- src/presentation/opening/ProblemLoopScene.test.tsx src/presentation/SceneBody.test.tsx ``` Expected: PASS. - [ ] **Step 8: Commit** ```bash git add web/apps/console/src/presentation/opening/ProblemLoopScene.tsx web/apps/console/src/presentation/opening/ProblemLoopScene.test.tsx 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: add presentation problem visual" ``` --- ### Task 4: Visual Smoke, Docs, And Archive **Files:** - Modify: `docs/current_roadmap.md` - Move: `docs/superpowers/plans/2026-07-10-presentation-opening-visuals.md` to `docs/historical/superpowers/plans/2026-07-10-presentation-opening-visuals.md` **Interfaces:** - Consumes: Tasks 1-3 complete. - Produces: completed roadmap entry and archived implementation plan. - [ ] **Step 1: Run full presentation tests** Run: ```bash pnpm --dir web --filter @lda/console test -- src/presentation ``` Expected: PASS. If route-level tests fail because text moved from narrative to diagrams, update tests to assert semantic labels (`AI agent decomposition`, `action sequence versus reusable automation`) rather than exact text position. - [ ] **Step 2: Run typecheck** Run: ```bash pnpm --dir web --filter @lda/console typecheck ``` Expected: PASS. - [ ] **Step 3: Run build** Run: ```bash pnpm --dir web --filter @lda/console build ``` Expected: PASS. The existing Vite chunk-size warning is acceptable. - [ ] **Step 4: Run React Doctor on changed React files** Run from `web/apps/console`: ```bash npx react-doctor@latest --verbose --scope changed ``` Expected: no new Critical/Important issues. Fix warnings if they are caused by this slice and are not false positives. - [ ] **Step 5: Capture visual smoke screenshots** Run: ```bash pnpm dlx playwright screenshot --viewport-size="1280,720" "http://127.0.0.1:5173/present#scene/thesis/title" web/apps/console/.visual-smoke/opening-01-title.png pnpm dlx playwright screenshot --viewport-size="1280,720" "http://127.0.0.1:5173/present#scene/thesis/substrate" web/apps/console/.visual-smoke/opening-01-substrate.png pnpm dlx playwright screenshot --viewport-size="1280,720" "http://127.0.0.1:5173/present#scene/problem/direct-actions" web/apps/console/.visual-smoke/opening-02-actions.png pnpm dlx playwright screenshot --viewport-size="1280,720" "http://127.0.0.1:5173/present#scene/problem/missing-contracts" web/apps/console/.visual-smoke/opening-02-automation.png ``` Expected: screenshots render without blank areas, clipped text, or text-only walls. `.visual-smoke/` is ignored and should not be committed. - [ ] **Step 6: Update roadmap** Modify `docs/current_roadmap.md` under `Recommended next visual slices`: ```md 1. Completed: Opening visuals rebuilt Scenes 1 and 2 around concrete diagrams for "AI-agent pursuit -> workflow substrate" and "direct actions are not reusable automation". Design: [`presentation opening visuals`](superpowers/specs/2026-07-10-presentation-opening-visuals-design.md). Implementation: [`presentation opening visuals plan`](historical/superpowers/plans/2026-07-10-presentation-opening-visuals.md). ``` - [ ] **Step 7: Archive the plan** Run: ```bash git mv docs/superpowers/plans/2026-07-10-presentation-opening-visuals.md docs/historical/superpowers/plans/2026-07-10-presentation-opening-visuals.md ``` - [ ] **Step 8: Commit docs/archive** ```bash git add docs/current_roadmap.md docs/historical/superpowers/plans/2026-07-10-presentation-opening-visuals.md git commit -m "docs: complete presentation opening visuals" ``` --- ## Self-Review Checklist - Spec coverage: - Scene 1 title reveal and contribution focus: Task 2. - Scene 2 action sequence vs reusable automation: Task 3. - Icons/shapes instead of text-only lists: Tasks 1-3. - No `wf` opening branding: Task 2 tests and spec constraints. - `Codex / Claude / OpenCode`: Task 2. - No formal lifecycle names in Scene 2: Task 3 tests. - Scenes 3/4/5 untouched: Global constraints and tasks only route `thesis`/`problem`. - Placeholder scan: - No unresolved placeholder markers or unspecified "handle errors" steps. - Dependency check: - No shadcn/ui dependency is added. This is deliberate because shadcn is a copied-source component-system decision, not a one-slide icon dependency. - Type consistency: - `ConceptIconName`, `ConceptIcon`, `ConceptNode`, and `ConceptRail` are defined in Task 1 and consumed by Tasks 2 and 3.