feat: give opening scenes a clear visual focal point

This commit is contained in:
lda
2026-07-11 09:19:15 +07:00 Verified
parent 9b9209fc36
commit 5e17d3e0c0
6 changed files with 112 additions and 31 deletions
@@ -8,9 +8,12 @@ const thesisScene = findScene("thesis")!;
afterEach(() => cleanup());
describe("OpeningThesisScene", () => {
it("renders the title reveal with latent component icons", () => {
it("makes the title boundary the opening focal artifact", () => {
render(<OpeningThesisScene scene={thesisScene} beat={findBeat("thesis", "title")!} />);
const opening = screen.getByRole("region", { name: /thesis opening/i });
expect(opening).toHaveAttribute("data-opening-focus", "title");
expect(opening).toHaveAttribute("data-support-state", "receded");
expect(screen.getByRole("heading", { name: /Design and Implementation of lda\.chat/i })).toBeInTheDocument();
expect(screen.getByText("Planner")).toBeInTheDocument();
expect(screen.getByText("Tool Surface")).toBeInTheDocument();
@@ -23,6 +26,9 @@ describe("OpeningThesisScene", () => {
it("renders contribution focus without relying on lda.chat as category label", () => {
render(<OpeningThesisScene scene={thesisScene} beat={findBeat("thesis", "substrate")!} />);
const opening = screen.getByRole("region", { name: /thesis opening/i });
expect(opening).toHaveAttribute("data-opening-focus", "substrate");
expect(opening).toHaveAttribute("data-support-state", "revealed");
expect(screen.getByText("Codex / Claude / OpenCode")).toBeInTheDocument();
expect(screen.getByText("CLI / MCP / APIs")).toBeInTheDocument();
expect(screen.getByText("submitted substrate")).toBeInTheDocument();
@@ -18,35 +18,39 @@ export const OpeningThesisScene = ({ scene, beat }: OpeningThesisSceneProps) =>
</StageCaption>
<section
className="opening-thesis"
aria-label="AI agent decomposition"
aria-label="thesis opening"
data-opening-beat={beat.id}
data-opening-focus={contributionBeat ? "substrate" : "title"}
data-support-state={contributionBeat ? "revealed" : "receded"}
>
<div className="opening-thesis__title-card">
<div className="opening-thesis__title-card" data-opening-role="title">
<span>AI agent for workspace workflows</span>
<strong>{contributionBeat ? "Decomposed" : scene.title}</strong>
</div>
<ConceptRail label="AI agent components">
<ConceptNode
title="Planner"
subtitle="Codex / Claude / OpenCode"
icon="planner"
emphasis={contributionBeat ? "muted" : "normal"}
/>
<ConceptNode
title="Tool Surface"
subtitle="CLI / MCP / APIs"
icon="tool"
emphasis={contributionBeat ? "muted" : "normal"}
/>
<ConceptNode
title="Workflow Platform"
subtitle="submitted substrate"
icon="platform"
emphasis="primary"
>
<span>Typed · Durable · Inspectable</span>
</ConceptNode>
</ConceptRail>
<div className="opening-thesis__decomposition">
<ConceptRail label="AI agent components">
<ConceptNode
title="Planner"
subtitle="Codex / Claude / OpenCode"
icon="planner"
emphasis={contributionBeat ? "muted" : "normal"}
/>
<ConceptNode
title="Tool Surface"
subtitle="CLI / MCP / APIs"
icon="tool"
emphasis={contributionBeat ? "muted" : "normal"}
/>
<ConceptNode
title="Workflow Platform"
subtitle="submitted substrate"
icon="platform"
emphasis="primary"
>
<span>Typed · Durable · Inspectable</span>
</ConceptNode>
</ConceptRail>
</div>
</section>
<p className="scene-body__evidence">{scene.evidencePointer}</p>
</>
@@ -12,6 +12,9 @@ describe("ProblemLoopScene", () => {
it("uses the assistant transcript surface for the direct-action side", async () => {
render(<ProblemLoopScene scene={problemScene} beat={findBeat("problem", "direct-actions")!} />);
const scene = screen.getByRole("region", { name: /chat tool loop versus reusable automation/i });
expect(scene).toHaveAttribute("data-problem-focus", "tool-loop");
expect(scene).toHaveAttribute("data-support-state", "quiet");
const transcript = screen.getByRole("log", { name: /one-off assistant transcript/i });
expect(transcript).toHaveClass("assistant-operator-thread");
expect(within(transcript).getByText("Can you finish this workspace task?")).toBeInTheDocument();
@@ -23,6 +26,9 @@ describe("ProblemLoopScene", () => {
it("renders reusable automation as a durable workflow blueprint", () => {
render(<ProblemLoopScene scene={problemScene} beat={findBeat("problem", "missing-contracts")!} />);
const scene = screen.getByRole("region", { name: /chat tool loop versus reusable automation/i });
expect(scene).toHaveAttribute("data-problem-focus", "workflow-blueprint");
expect(scene).toHaveAttribute("data-support-state", "receded");
const blueprint = screen.getByRole("group", { name: /durable workflow blueprint/i });
expect(blueprint).toHaveAttribute("data-blueprint-active", "true");
@@ -58,10 +58,16 @@ export const ProblemLoopScene = ({ scene, beat }: ProblemLoopSceneProps) => {
<StageCaption eyebrow="Problem shape" title={scene.title}>
<p>{beat.caption}</p>
</StageCaption>
<section className="problem-loop-scene" aria-label="chat tool loop versus reusable automation">
<section
className="problem-loop-scene"
aria-label="chat tool loop versus reusable automation"
data-problem-focus={automationBeat ? "workflow-blueprint" : "tool-loop"}
data-support-state={automationBeat ? "receded" : "quiet"}
>
<article
className="problem-chat-card"
data-problem-active={automationBeat ? "false" : "true"}
data-problem-role="tool-loop"
aria-label="one-off chat and tool loop"
>
<header className="problem-artifact-header">
@@ -75,13 +81,14 @@ export const ProblemLoopScene = ({ scene, beat }: ProblemLoopSceneProps) => {
<p className="problem-artifact-note">The useful work lives in the conversation history.</p>
</article>
<div className="problem-loop-scene__bridge" aria-hidden="true"></div>
<div className="problem-loop-scene__bridge" aria-hidden="true">one request durable definition</div>
<article
className="problem-blueprint"
role="group"
aria-label="durable workflow blueprint"
data-blueprint-active={automationBeat ? "true" : "false"}
data-problem-role="workflow-blueprint"
>
<header className="problem-artifact-header">
<span>Reusable</span>