Files
lda-wf/docs/superpowers/specs/2026-07-08-presentation-alignment-layout-polish-design.md
T

218 lines
6.4 KiB
Markdown

# Presentation Alignment And Layout Polish Design
## Purpose
The presentation route now has stronger scene compositions, but two classes of
visual problems remain:
- Scene 6's React Flow architecture figure can show node/edge offset because
Dagre layout dimensions do not match the rendered stage-node dimensions.
- Several presentation surfaces can visually collide or float awkwardly:
discussion chips overlap Scene 3 evidence text, and chat rail behavior is
awkward in narrower 4:3-adjacent layouts.
This slice fixes alignment and collision problems that make the presentation
look broken. It does not replace the chat framework or redesign the whole
presentation style.
## Scope
In scope:
- React Flow architecture figure alignment in Scene 6.
- Size-aware Dagre layout dimensions for `InteractiveFigure`.
- A more stable `fitView` timing after layout/container changes.
- Scene discussion chip/evidence collision prevention.
- 4:3-adjacent chat rail behavior so chat does not float detached beside the
slide.
- Correct Scene 10 approval smoke route: `#scene/interrupt-evidence/approval`.
- Focused tests plus screenshot smoke.
Out of scope:
- Replacing chat with AI SDK/AI Elements or another chat framework.
- Redesigning tool-call bubbles.
- Rewriting the recursive figure catalog.
- Replacing React Flow or Dagre.
- Building a presenter companion.
- Full motion choreography.
## Design Direction
Treat this as a correctness and layout-stability slice. The goal is not to make
every slide beautiful; the goal is to stop visible misalignment and collision.
The implementation should be conservative:
- Keep React Flow.
- Keep Dagre.
- Keep existing scene data and storyboard hashes.
- Add size-aware layout only where the rendered node dimensions differ.
- Use CSS custom properties or exported TypeScript presets so layout math and
CSS stay in sync.
- Prefer simple layout rules over clever responsive choreography.
## Figure Alignment
Current problem:
- `figures/layout.ts` lays out every auto-layout figure as `236 x 102`.
- `interactive-figure.css` renders stage figure nodes as `256 x 112`.
- Scene 6 uses `size="stage"`.
That mismatch means Dagre calculates node centers for one box while React Flow
renders a larger box. Edge anchors and node centers can drift.
Required behavior:
- `layoutFigure` accepts an optional size preset or dimensions.
- Standard/wide figures keep `236 x 102`.
- Stage figures use `256 x 112`.
- `InteractiveFigure` passes the layout size based on its `size` prop.
- CSS node dimensions and TypeScript layout dimensions are explicitly aligned.
Implementation preference:
```ts
export type FigureLayoutSize = "standard" | "wide" | "stage";
export const FIGURE_NODE_DIMENSIONS: Record<FigureLayoutSize, {
readonly width: number;
readonly height: number;
}> = {
standard: { width: 236, height: 102 },
wide: { width: 236, height: 102 },
stage: { width: 256, height: 112 },
};
```
Then:
```ts
layoutFigure(focus.figure, size)
```
The exact type names can differ, but the concept should be explicit and tested.
## FitView Timing
Current behavior:
- `FitViewOnLayoutChange` calls `fitView()` once in an effect.
Problem:
- In stage mode, the canvas, container query, scroll container, breadcrumb row,
and parent presentation scale can all settle after first render. A single
immediate `fitView()` can measure too early.
Required behavior:
- Keep the immediate `fitView`.
- Schedule a second `fitView` with `requestAnimationFrame`.
- Clean up/cancel the frame on unmount or layout-key change.
- Do not add a large measurement framework in this slice.
The second call should be tiny and commented, because it is deliberately
working around layout settlement timing around React Flow.
## Discussion Chip Collision
Current problem:
- Scene 3 screenshots show discussion chips overlapping the evidence label at
the bottom-left.
Required behavior:
- Evidence text and discussion chips must not overlap at 1280x720.
- Discussion chips remain available but secondary.
- The fix should work for all scenes, not only Scene 3.
Acceptable design:
- Make the primary scene region reserve bottom space for chips.
- Move evidence text above chips when both are present.
- Or make the discussion chip lane participate in normal layout instead of
absolute/fixed positioning.
Do not hide discussion chips entirely.
## 4:3-Adjacent Chat Rail
Current problem:
- On slides with chat, narrower canvas ratios can make the chat rail feel like
a floating, detached side object.
Required behavior:
- At narrower presentation canvas widths, chat rail should become a compact
dock/overlay instead of a detached side rail.
- This should be CSS-driven where possible.
- The standard 1280x720 view should not regress.
Acceptable design:
- Use existing `data-chat-mode` and stage width/container queries.
- For narrow layouts, position chat as a bottom-left compact dock with a
bounded width and max height.
- Keep it readable and out of the primary diagram path.
Do not add new chat state or a new chat framework.
## Scene 10 Smoke Route
The correct approval route is:
```text
/present#scene/interrupt-evidence/approval
```
The route below is invalid and must not be used in live specs or future smoke
commands:
```text
/present#scene/workflow-demo/approval
```
## Verification
Required focused tests:
```powershell
pnpm --dir web --filter @lda/console test -- src/presentation/figures/layout.test.ts src/presentation/figures/InteractiveFigure.test.tsx src/presentation/PresentationStage.test.tsx src/presentation/SceneBody.test.tsx
pnpm --dir web --filter @lda/console typecheck
pnpm --dir web --filter @lda/console build
```
Required screenshot smoke:
- `/present#scene/architecture/client`
- `/present#scene/architecture/runtime`
- `/present#scene/positioning/landscape`
- `/present#scene/positioning/lda-position`
- `/present#scene/interrupt-evidence/approval`
Capture at:
- `1280x720`.
- `1024x768`.
Save screenshots under `web/apps/console/.visual-smoke/`.
Acceptance checks:
- Scene 6 nodes and edges visually align.
- Scene 6 stage figure remains keyboard navigable.
- Scene 3 evidence and discussion chips do not overlap.
- Slides with chat do not show an obviously detached floating rail at 1024x768.
- Scene 10 screenshot opens Scene 10, not Scene 1 fallback.
## Self-Review
- No placeholders remain.
- The slice is bounded to visual correctness and layout stability.
- The design does not require replacing React Flow, Dagre, or chat.
- The corrected Scene 10 route is explicit.