Files
lda-wf/docs/superpowers/specs/2026-07-03-react-presentation-mode-design.md
T

9.8 KiB

React Presentation Mode Design

Status

Current design contract for the next Workflow Console slice.

Purpose

The console can now run and replay the prepared lda_report_workflow, but the screen still reads as a debug console. The defense needs a route that can explain the product quickly, survive 720p projection, and answer questions without forcing the viewer through raw JSON.

This slice adds a React presentation mode inside web/apps/console. It is not a separate slide framework. It is a staged compositor over real React components: chat, workflow graph, operation evidence, typed interrupt approval, report output, trace, and captions can enter, leave, or take focus as scripted beats advance.

The first implementation is not expected to be the final defense script. It should establish the presentation infrastructure and use a provisional script that can be revised cheaply. The target editing experience is that adding or changing a beat is a small semantic change, not a rewrite of a large TSX file. For example, selecting a workflow node and showing its NodeUse detail should be expressed as a short beat/state edit, with the reusable graph and spotlight components handling the rest.

Product Boundary

The normal console remains the real product surface: dense, inspectable, operator-facing, and evidence-first.

Presentation mode is a defense-stage surface over the same data and controller. It may use replay by default, but it must not pretend a live LLM is making planning decisions. The chat persona is scripted/replayed operator interaction unless a later constrained macro explicitly runs.

Terminology:

  • Console: ordinary workflow product UI.
  • Presentation mode: cinematic staged route inside the React app.
  • Beat: one named presentation moment.
  • Scene component: a React component that renders one visible part of the stage.
  • Operation block: a visible product call with raw and interpreted output.
  • Presentation agent: scripted/replayed operator persona.
  • Constrained demo agent: optional future macro client.
  • External LLM agent: out of scope for the defense UI.

Route

Add a dedicated route inside the console app:

/present

The existing console page remains available separately. The exact console route may be /console or the current root route, but presentation mode must not be a mode toggle that permanently compromises the console layout.

Hash fragments select scripted beats:

/present#intro
/present#graph-reveal
/present#interrupt-approval
/present#trace-evidence

Hash navigation is preferred over query parameters because it is easy to copy during rehearsal, has no server-routing implications, and can survive a future static shell.

Interaction Model

Presentation mode is a hybrid of scripted beats and manual inspection.

Primary controls:

  • Space / ArrowRight: next beat.
  • ArrowLeft: previous scripted beat.
  • Esc: close the current overlay or evidence inspector.
  • Mouse/touch: inspect node, open evidence, submit approval, or jump timeline.

Backward navigation only rewinds visual/script state. It must not undo live workflow mutations. If the current run was live, going backward replays the stored stage state for explanation, not runtime rollback.

Replay mode is the default. Live mode is available but explicit.

Stage Model

Avoid building a generic layout engine. Beats should be semantic state, and components should decide their own motion and layout.

Acceptable state shape:

type BeatId =
  | "intro"
  | "chat-request"
  | "tool-call-start"
  | "graph-reveal"
  | "interrupt-approval"
  | "resume-output"
  | "trace-evidence"
  | "boundary-wrap";

type PresentationState = {
  readonly beat: BeatId;
  readonly selectedNodeId: string | null;
  readonly chatMode: "full" | "rail" | "hidden";
  readonly evidenceMode: "hidden" | "peek" | "open";
  readonly playbackMode: "replay" | "live";
};

Do not store React components or large layer configuration objects inside beat data. The route rerenders normal React components from semantic state. CSS and motion handle the choreography.

Components

Keep the TSX files lean. Presentation behavior should be split into focused components:

presentation/
  PresentationRoute
  PresentationStage
  BeatController
  BeatRail
  StageCaption
  OperatorChat
  ChatMessage
  OperationBlock
  WorkflowGraphStage
  NodeSpotlight
  ApprovalScene
  ReportOutputScene
  TraceEvidenceScene
  EvidenceDrawer

The first implementation does not need every component above, but the route should not become a single large TSX file.

Component extraction from the existing console/demo UI is in scope for the first slice when it prevents duplicate graph, timeline, operation evidence, output, or trace rendering. This is maintenance reduction, not optional polish: presentation mode and console mode should share the useful product components while keeping their layout/composition separate.

Beat Outline

The first script should stay under eight beats:

  1. Intro: claim frame: planner decisions are separated from deterministic runtime execution.
  2. Chat request: operator asks for the thesis readiness report.
  3. Tool call start: lda.chat runs the prepared workflow operation.
  4. Graph reveal: workflow graph becomes primary; chat moves to a rail.
  5. Interrupt approval: typed issue_review appears as an explicit human boundary.
  6. Resume output: selected issue and markdown report are produced.
  7. Trace evidence: trace and raw/interpreted evidence show inspectability.
  8. Boundary wrap: clarify substrate versus autonomous agent claims.

Each beat should have one short caption. Avoid prose blocks. In Q&A, the operator should be able to jump directly to graph, interrupt, trace, or evidence beats.

Operation Block

Operation calls are first-class presentation elements. They bridge chat and the workflow substrate.

An operation block shows:

  • equivalent CLI or JSON-RPC method;
  • compact raw request/response;
  • interpreted result;
  • affected workflow/run ids;
  • status and duration when available.

Example presentation:

$ uv run wf run start lda_report_case_study.default --input-file run-input.json

raw:
{ "status": "interrupted", "interrupt": { "kind": "issue_review" } }

interpreted:
Human approval required
1 proposed issue
Resume outcomes: submitted | cancelled

The block can appear compact inside chat and expand into a terminal-like panel. The interpreted side may highlight graph nodes or stage elements. Raw evidence remains available through the global evidence inspector.

Graph

Use a curated presentation graph backed by real workflow/run evidence.

The presentation graph may use clearer labels and positions than the raw plan, but it must not invent steps that do not exist. Each visible node should be able to point to one of:

  • a workflow node id;
  • a run trace frame;
  • an operation block;
  • a captured replay event.

Clicking a node can open NodeSpotlight, which shows the node purpose, input/output summary, and related evidence.

Motion

Motion should make state changes understandable:

  • chat can enter full-screen, then scoot into a rail;
  • graph can bloom into the main stage;
  • a clicked node can expand into a detail panel;
  • evidence can peek from the side, then open;
  • beat rail progress can advance subtly.

No slow typewriter effect. Chat messages appear as complete messages with a small fade or stagger. This resembles modern AI app streaming enough without wasting defense time or implying a live model.

Every motion path needs a reduced-motion fallback.

Visual Stack

Use React first. Add routing and motion before adopting a large component library.

Tailwind-style utilities and copy-owned components such as shadcn/ui are acceptable if they help speed up consistent layout. Avoid adopting a full chat or agent framework until runtime agent behavior exists. Templates may be copied as raw material, but the visual result should fit the lda.chat stage, not a generic SaaS/chat clone.

720p Constraint

Design for a 720px logical height and adaptive logical widths from 960px through 1280px. See the adaptive presentation canvas design.

Rules:

  • one primary object per beat;
  • one secondary detail at most;
  • captions must be short;
  • raw evidence is collapsed by default;
  • long code/output wraps inside panels;
  • the presenter must not need browser zoom during the main path.

Testing

Unit tests should cover:

  • beat reducer/state transitions;
  • hash-to-beat and beat-to-hash behavior;
  • keyboard controls;
  • replay-default startup;
  • backward navigation does not call live mutation operations;
  • operation block rendering for CLI/raw/interpreted output.

Browser smoke should cover:

  1. load /present;
  2. verify replay is the default;
  3. advance through all beats with keyboard;
  4. open node spotlight;
  5. open the evidence inspector;
  6. jump to #interrupt-approval;
  7. complete the replay path on 1024x768 and 1280x720 viewports;
  8. verify the normal console route still works.

Success Criteria

The slice is complete when:

  1. /present can run the prepared replay story without an RPC server;
  2. the same route can optionally use live mode when connected;
  3. keyboard controls can drive the main defense path;
  4. hash links jump to important beats;
  5. operation blocks make product calls visible and interpretable;
  6. graph, interrupt, output, trace, and evidence are available without clutter;
  7. the route is readable from 4:3 through 16:9 supported ratios;
  8. the normal console remains product-like and is not forced into cinematic layout choices.