6.4 KiB
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
fitViewtiming 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.tslays out every auto-layout figure as236 x 102.interactive-figure.cssrenders stage figure nodes as256 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:
layoutFigureaccepts an optional size preset or dimensions.- Standard/wide figures keep
236 x 102. - Stage figures use
256 x 112. InteractiveFigurepasses the layout size based on itssizeprop.- CSS node dimensions and TypeScript layout dimensions are explicitly aligned.
Implementation preference:
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:
layoutFigure(focus.figure, size)
The exact type names can differ, but the concept should be explicit and tested.
FitView Timing
Current behavior:
FitViewOnLayoutChangecallsfitView()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
fitViewwithrequestAnimationFrame. - 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-modeand 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:
/present#scene/interrupt-evidence/approval
The route below is invalid and must not be used in live specs or future smoke commands:
/present#scene/workflow-demo/approval
Verification
Required focused tests:
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.