docs: plan presentation scene composition
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,236 @@
|
||||
# Presentation Scene Composition Design
|
||||
|
||||
## Purpose
|
||||
|
||||
The presentation route now has readable side-surfaces, Q&A panels, and a usable
|
||||
architecture figure. The weakest remaining slides are not primarily contrast
|
||||
problems. Scenes 3, 4, and 5 underuse the 720p stage: their content sits in a
|
||||
thin strip near the top while the rest of the canvas is empty. Scene 10 has a
|
||||
working demo composition, but important graph and interrupt-contract details
|
||||
are still too dim.
|
||||
|
||||
This slice improves composition before doing any deeper visual craft pass. The
|
||||
goal is to make the slides understandable from the back of a room at 1280x720
|
||||
without changing storyboard content, transport behavior, chat architecture, or
|
||||
demo state.
|
||||
|
||||
## Scope
|
||||
|
||||
In scope:
|
||||
|
||||
- Scene 3, Positioning and Related Systems.
|
||||
- Scene 4, Planner and Runtime.
|
||||
- Scene 5, Workflow Lifecycle.
|
||||
- Light Scene 10 readability/proportion tuning for the graph and interrupt
|
||||
contract.
|
||||
- Scene-specific tests that assert the new structural roles and beat-driven
|
||||
emphasis.
|
||||
- Screenshot smoke for the affected scenes at 1280x720.
|
||||
- Roadmap update and implementation-plan archival after execution.
|
||||
|
||||
Out of scope:
|
||||
|
||||
- Chat framework replacement.
|
||||
- Q&A content rewrites.
|
||||
- Evidence inspector redesign.
|
||||
- New presentation routes or presenter companion controls.
|
||||
- Replacing the architecture recursive figure system.
|
||||
- General motion polish. Motion should remain simple and state-driven.
|
||||
|
||||
## Design Direction
|
||||
|
||||
Use bespoke scene compositions, not a new generic diagram framework. The current
|
||||
problem is concrete: three scenes lack enough spatial structure. Abstraction can
|
||||
wait until multiple scenes prove they share the same durable shape.
|
||||
|
||||
The stage should feel like an editorial product walkthrough:
|
||||
|
||||
- A large visual object carries the scene.
|
||||
- Beat changes emphasize different regions of that object.
|
||||
- Discussion chips stay available but do not compete with the central diagram.
|
||||
- Evidence labels remain small and supportive.
|
||||
- Typography stays readable and restrained; no extra display fonts or decorative
|
||||
visual effects are needed.
|
||||
|
||||
## Scene 3: Positioning Map
|
||||
|
||||
Scene 3 should become a wide positioning map rather than five equal cards.
|
||||
|
||||
Structure:
|
||||
|
||||
- Left column: direct action patterns.
|
||||
- Tool loops.
|
||||
- Generated scripts.
|
||||
- Center: `lda.chat` as the workflow substrate.
|
||||
- Larger than the surrounding entries.
|
||||
- Uses the language "typed lifecycle substrate" or equivalent.
|
||||
- Shows three owned responsibilities: lifecycle, validation, persisted
|
||||
records.
|
||||
- Right column: adjacent orchestration ecosystems.
|
||||
- Hosted automation.
|
||||
- Agent graphs.
|
||||
- MCP / capability protocols.
|
||||
|
||||
Beat behavior:
|
||||
|
||||
- `landscape`: show the full map with no one region overpowering the others.
|
||||
- `lda-position`: emphasize the center substrate and dim surrounding entries
|
||||
slightly.
|
||||
|
||||
Testing expectations:
|
||||
|
||||
- The positioning scene exposes an accessible region such as
|
||||
`aria-label="positioning map"`.
|
||||
- The `lda-position` beat marks the center node active, for example through
|
||||
`data-positioning-active="true"`.
|
||||
- The map contains the labels `Tool loops`, `Generated scripts`, `lda.chat`,
|
||||
`Agent graphs`, and `MCP`.
|
||||
|
||||
## Scene 4: Planner Runtime Boundary
|
||||
|
||||
Scene 4 should make the boundary itself the main visual object.
|
||||
|
||||
Structure:
|
||||
|
||||
- Two large panes fill the stage width:
|
||||
- Planner pane: "proposes", "revises", "chooses tools".
|
||||
- Runtime pane: "validates", "executes", "records", "resumes".
|
||||
- A central boundary seam separates them.
|
||||
- A small handoff strip or arrow names the interface: CLI / JSON-RPC / workflow
|
||||
operations.
|
||||
|
||||
Beat behavior:
|
||||
|
||||
- `planner`: planner pane is active, runtime pane stays visible but reduced.
|
||||
- `runtime`: runtime pane is active, planner pane stays visible but reduced.
|
||||
- `boundary`: both sides are active and the seam/interface is emphasized.
|
||||
|
||||
Testing expectations:
|
||||
|
||||
- The scene exposes an accessible region such as
|
||||
`aria-label="planner runtime boundary"`.
|
||||
- The active beat is reflected in a stable attribute, for example
|
||||
`data-boundary-active="planner" | "runtime" | "boundary"`.
|
||||
- The boundary interface text includes both `CLI` and `JSON-RPC`.
|
||||
|
||||
## Scene 5: Lifecycle Rail
|
||||
|
||||
Scene 5 should become a full-width lifecycle rail with large state blocks and a
|
||||
small explanation panel for the current beat.
|
||||
|
||||
Structure:
|
||||
|
||||
- Four large lifecycle blocks:
|
||||
- Draft.
|
||||
- Artifact.
|
||||
- Deployment.
|
||||
- Run.
|
||||
- Directional connectors between blocks.
|
||||
- A current-state explanation panel below or beside the rail.
|
||||
- Each block has one concise responsibility:
|
||||
- Draft: mutable authoring state.
|
||||
- Artifact: immutable workflow definition.
|
||||
- Deployment: source binding.
|
||||
- Run: execution record and trace.
|
||||
|
||||
Beat behavior:
|
||||
|
||||
- Each beat activates its matching block and explanation panel.
|
||||
- Previous blocks can be marked as completed, but inactive future blocks must
|
||||
remain readable.
|
||||
- Raw-plan bypass should be mentioned only in discussion/Q&A, not in the core
|
||||
rail, to avoid crowding the scene.
|
||||
|
||||
Testing expectations:
|
||||
|
||||
- The lifecycle scene exposes `aria-label="workflow lifecycle rail"`.
|
||||
- The active block has `data-lifecycle-active="true"` or equivalent.
|
||||
- The current explanation text changes across at least two beats.
|
||||
|
||||
## Scene 10: Demo Graph And Contract Tuning
|
||||
|
||||
Scene 10 already has a working demo composition. This slice should only tune
|
||||
proportions and readability.
|
||||
|
||||
Changes:
|
||||
|
||||
- Increase graph node text contrast.
|
||||
- Ensure completed/current/interrupt labels are readable at 1280x720.
|
||||
- Keep graph and contract panel balanced; neither should collapse into a tiny
|
||||
subpanel.
|
||||
- In interrupt/approval beats, the interrupt contract must be visually
|
||||
available without forcing the viewer to inspect tiny JSON.
|
||||
|
||||
Testing expectations:
|
||||
|
||||
- Existing demo scene tests should continue to pass.
|
||||
- Add or update a test that asserts the approval beat exposes a readable
|
||||
contract panel label.
|
||||
- Do not add new demo state, new RPC calls, or new recording data in this slice.
|
||||
|
||||
## CSS And Component Boundaries
|
||||
|
||||
Expected files:
|
||||
|
||||
- `web/apps/console/src/presentation/SceneBody.tsx`
|
||||
- Rewrite the positioning, planner-runtime, and lifecycle scene renderers.
|
||||
- `web/apps/console/src/presentation/SceneBody.test.tsx`
|
||||
- Add structure and beat-state tests.
|
||||
- `web/apps/console/src/presentation/presentation.css`
|
||||
- Replace the old small-card rules for these scenes.
|
||||
- `web/apps/console/src/presentation/DemoWorkflowScene.tsx`
|
||||
- Only modify if a small structural hook is needed for Scene 10 tuning.
|
||||
- `web/apps/console/src/presentation/styles/demo-workflow.css`
|
||||
- Tune Scene 10 graph/contract readability.
|
||||
|
||||
Avoid creating a new generic component library in this slice unless the helper
|
||||
is tiny and scene-local. The implementation should remain easy for the next
|
||||
agent to reason about.
|
||||
|
||||
## Visual Acceptance Criteria
|
||||
|
||||
At 1280x720:
|
||||
|
||||
- Scene 3 uses the middle of the canvas and reads as a map, not a row of cards.
|
||||
- Scene 4 clearly communicates the planner/runtime division without reading the
|
||||
slide text.
|
||||
- Scene 5 clearly communicates Draft -> Artifact -> Deployment -> Run.
|
||||
- Scene 10's graph labels and interrupt-contract area are readable without
|
||||
zooming.
|
||||
- Discussion chips remain visible but secondary.
|
||||
- No horizontal or vertical stage scrollbars appear.
|
||||
|
||||
At 1024x768:
|
||||
|
||||
- Scene content may become denser, but labels must not overlap.
|
||||
- The lifecycle rail may wrap only if needed; if it wraps, direction must remain
|
||||
understandable.
|
||||
|
||||
## Verification
|
||||
|
||||
Required focused commands:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Required screenshot smoke:
|
||||
|
||||
- `/present#scene/positioning/landscape`
|
||||
- `/present#scene/positioning/lda-position`
|
||||
- `/present#scene/planner-runtime/planner`
|
||||
- `/present#scene/planner-runtime/boundary`
|
||||
- `/present#scene/lifecycle/draft`
|
||||
- `/present#scene/lifecycle/run`
|
||||
- `/present#scene/workflow-demo/approval`
|
||||
|
||||
Save screenshots under `web/apps/console/.visual-smoke/`, which is ignored.
|
||||
|
||||
## Self-Review
|
||||
|
||||
- No placeholders remain.
|
||||
- The slice is intentionally limited to composition and readability.
|
||||
- Scene 10 is a tune-up, not a demo-system rewrite.
|
||||
- The spec does not require a new shared component framework.
|
||||
@@ -0,0 +1,108 @@
|
||||
# Presentation Surface Theme Normalization Design
|
||||
|
||||
## Purpose
|
||||
|
||||
The previous contrast pass fixed dark-on-dark text, but it did not make the
|
||||
presentation side-surfaces feel coherent. Chat can become too white, while
|
||||
discussion/Q&A panels still use a dark modal interior. This slice normalizes
|
||||
those surfaces so `/present` reads as one editorial product walkthrough instead
|
||||
of multiple unrelated UI skins.
|
||||
|
||||
## Scope
|
||||
|
||||
In scope:
|
||||
|
||||
- Chat rail and chat message surface styling.
|
||||
- Discussion panel and Q&A branch styling.
|
||||
- Presenter-note styling inside discussion panels.
|
||||
- Shared presentation-only CSS hooks for editorial and night side-surfaces.
|
||||
- Screenshot smoke for representative scenes and direct discussion hashes.
|
||||
|
||||
Out of scope:
|
||||
|
||||
- Replacing chat with AI Elements or another chat framework.
|
||||
- Scene 6/7/10 composition changes.
|
||||
- Schema form approval UI.
|
||||
- Guided run beat gates.
|
||||
- Presenter companion.
|
||||
- Global `/console` theme changes.
|
||||
|
||||
## Design Direction
|
||||
|
||||
Use one restrained editorial surface vocabulary for presentation side-surfaces:
|
||||
|
||||
- **Editorial surface**: off-paper, slightly tinted, readable dark ink, subtle
|
||||
border, used for light chat and discussion panels.
|
||||
- **Night surface**: dark, readable text, restrained cyan/amber accents, used
|
||||
only when a beat intentionally lives on the dark workflow stage.
|
||||
|
||||
Do not let chat become pure white cards floating on paper. Do not let discussion
|
||||
modals look like old dark dashboard cards when opened from paper scenes. The
|
||||
modal should feel like a focused editorial note: readable, calm, and connected
|
||||
to the presentation canvas.
|
||||
|
||||
## Surface Contract
|
||||
|
||||
Components that render side-surfaces should expose a semantic surface attribute:
|
||||
|
||||
```tsx
|
||||
data-presentation-surface="editorial" | "night"
|
||||
```
|
||||
|
||||
This is not a full theme system. It is a small CSS contract for presentation
|
||||
side-surfaces. It should live on:
|
||||
|
||||
- `OperatorChat`
|
||||
- `DiscussionPanel`
|
||||
|
||||
Existing `data-chat-theme` may remain for compatibility, but CSS should prefer
|
||||
the semantic surface attribute for visual styling.
|
||||
|
||||
## Chat
|
||||
|
||||
Light chat should use the editorial surface, not white cards. The chat rail
|
||||
should be readable but secondary to the graph/evidence surfaces.
|
||||
|
||||
Required:
|
||||
|
||||
- `OperatorChat` maps `chatTheme === "light"` to
|
||||
`data-presentation-surface="editorial"`.
|
||||
- Chat cards on the editorial surface use off-paper background and dark ink.
|
||||
- Tool-call parts inside chat use the same surface, border, and text rules.
|
||||
- Night chat stays readable with dark cards and light text.
|
||||
|
||||
## Discussion/Q&A
|
||||
|
||||
All direct `#discuss/...` routes should use the editorial surface by default.
|
||||
This keeps Q&A readable and avoids dark modal interiors on paper scenes.
|
||||
|
||||
Required:
|
||||
|
||||
- `DiscussionPanel` root uses `data-presentation-surface="editorial"`.
|
||||
- Title, badge, evidence pointer, summary, Q&A answer, details, links, return
|
||||
button, and presenter note all have explicit readable colors.
|
||||
- Presenter notes stay demoted: visible to presenter, not styled as the main
|
||||
answer.
|
||||
|
||||
## Testing And Smoke
|
||||
|
||||
Automated tests should pin the surface attributes and representative content.
|
||||
CSS color correctness is confirmed through screenshot smoke, not jsdom computed
|
||||
color assertions.
|
||||
|
||||
Screenshot smoke targets:
|
||||
|
||||
- `#scene/positioning/landscape`
|
||||
- `#scene/planner-runtime/planner`
|
||||
- `#scene/lifecycle/draft`
|
||||
- `#discuss/where-is-ai-agent`
|
||||
- `#discuss/evaluation-validity`
|
||||
- `#scene/interrupt-evidence/approval`
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Chat is not pure white unless intentionally inside a full paper scene.
|
||||
- Discussion panels are readable and editorial.
|
||||
- Q&A panels do not look like old dashboard modals.
|
||||
- Presenter notes are demoted but legible.
|
||||
- `/console` remains unaffected.
|
||||
@@ -30,12 +30,12 @@ describe("OperatorChat", () => {
|
||||
expect(chat).toHaveAttribute("data-presentation-surface", "night");
|
||||
});
|
||||
|
||||
it("exposes chat theme and readable surface attributes", () => {
|
||||
it("exposes semantic chat surface attributes", () => {
|
||||
render(<OperatorChat state={initialPresentationState} />);
|
||||
|
||||
const chat = screen.getByLabelText("scripted operator chat");
|
||||
expect(chat).toHaveAttribute("data-chat-theme");
|
||||
expect(chat).toHaveAttribute("data-readable-surface");
|
||||
expect(chat).not.toHaveAttribute("data-readable-surface");
|
||||
});
|
||||
|
||||
it("renders standard agent message parts", () => {
|
||||
|
||||
@@ -117,7 +117,6 @@ export const OperatorChat = ({ state, messages, onApprove, onDeny }: OperatorCha
|
||||
className="operator-chat"
|
||||
data-mode={composition.chatMode}
|
||||
data-chat-theme={composition.chatTheme}
|
||||
data-readable-surface={composition.chatTheme === "light" ? "light" : "dark"}
|
||||
data-presentation-surface={presentationSurface}
|
||||
aria-label="scripted operator chat"
|
||||
>
|
||||
|
||||
@@ -527,7 +527,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.discussion-panel {
|
||||
.discussion-panel[data-presentation-surface="editorial"] {
|
||||
padding: 1rem;
|
||||
border: 1px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 35%, transparent);
|
||||
border-radius: 0.75rem;
|
||||
@@ -535,13 +535,13 @@
|
||||
color: var(--color-editorial-ink, oklch(0.19 0.015 65));
|
||||
}
|
||||
|
||||
.discussion-panel h2 {
|
||||
.discussion-panel[data-presentation-surface="editorial"] h2 {
|
||||
font-size: 1.1rem;
|
||||
margin: 0 0 0.5rem;
|
||||
color: var(--color-editorial-ink, oklch(0.19 0.015 65));
|
||||
}
|
||||
|
||||
.discussion-panel__badge {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__badge {
|
||||
display: inline-block;
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 0.3rem;
|
||||
@@ -552,17 +552,17 @@
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.discussion-panel__evidence {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__evidence {
|
||||
font-size: 0.8rem;
|
||||
color: var(--color-editorial-muted, oklch(0.48 0.025 65));
|
||||
}
|
||||
|
||||
.discussion-panel__summary {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__summary {
|
||||
margin: 0.5rem 0;
|
||||
color: var(--color-editorial-ink, oklch(0.19 0.015 65));
|
||||
}
|
||||
|
||||
.discussion-panel__qna {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__qna {
|
||||
display: grid;
|
||||
gap: 0.6rem;
|
||||
margin: 0.75rem 0;
|
||||
@@ -572,25 +572,25 @@
|
||||
background: color-mix(in oklch, var(--color-editorial-paper, oklch(0.975 0.012 82)) 74%, white);
|
||||
}
|
||||
|
||||
.discussion-panel__question,
|
||||
.discussion-panel__short-answer {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__question,
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__short-answer {
|
||||
margin: 0;
|
||||
font-size: 1.02rem;
|
||||
font-weight: 750;
|
||||
color: var(--color-editorial-ink, oklch(0.19 0.015 65));
|
||||
}
|
||||
|
||||
.discussion-panel__short-answer {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__short-answer {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.discussion-panel__expanded-answer {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__expanded-answer {
|
||||
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)));
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.discussion-panel__presenter-note {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note {
|
||||
margin: 0;
|
||||
padding: 0.55rem 0.65rem;
|
||||
border: 1px dashed color-mix(in oklch, var(--color-human, oklch(0.68 0.17 55)) 38%, transparent);
|
||||
@@ -601,7 +601,7 @@
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.discussion-panel__presenter-note span {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__presenter-note span {
|
||||
display: block;
|
||||
margin-bottom: 0.2rem;
|
||||
color: color-mix(in oklch, var(--color-human, oklch(0.68 0.17 55)) 70%, var(--color-editorial-ink, oklch(0.19 0.015 65)));
|
||||
@@ -610,7 +610,7 @@
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.discussion-panel__detail {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__detail {
|
||||
font-size: 0.85rem;
|
||||
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)));
|
||||
border-left: 2px solid color-mix(in oklch, var(--color-editorial-muted, oklch(0.48 0.025 65)) 42%, transparent);
|
||||
@@ -618,7 +618,7 @@
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.discussion-panel__return {
|
||||
.discussion-panel[data-presentation-surface="editorial"] .discussion-panel__return {
|
||||
margin-top: 0.75rem;
|
||||
border: 1px solid var(--color-editorial-ink, oklch(0.19 0.015 65));
|
||||
border-radius: 0.4rem;
|
||||
|
||||
Reference in New Issue
Block a user