Design Journal — The Screenplay & DialogueDirector


🎯 Intent

What was I trying to achieve today?

  • Move pod markdown files into a self-contained content directory (content/pods/ikigai/).
  • Create a screenplay format that captures all hardcoded flow copy.
  • Make the DialogueDirector the sole authority on what gets said — the surface becomes a dumb renderer.
  • Implement bubble grouping for consecutive same-role messages.
  • Handle all lifecycle scenes: first visit, return visit, boot, resume, completion, close, and stage complete.

🧭 Guiding Questions

What questions are shaping my thinking right now?

  • What is the right boundary between the screenplay (content) and the director (logic)?
  • Should timing be a creative decision (screenplay) or a rendering concern (surface)?
  • How do we handle the transition when all pods are complete — is it an ending or a stage transition?
  • Where does the attention budget belong — in the screenplay or in the pod frontmatter?
  • Can the screenplay format evolve into something with explicit roles and stage directions?

🧠 Insight

What clicked?

  • The screenplay is a script, the director interprets it, the surface performs it. Clean separation of concerns.
  • Timing is a creative decision about how the conversation feels — it belongs in the screenplay, not the renderer.
  • stage_complete is the right name because it signals a transition to the next stage, not an ending. The Ikigai discovery is one stage in a larger journey.
  • The attention budget is a content design property of the pod, not a flow orchestration concern. The screenplay shouldn’t set it — but a future actor preference layer could override it.
  • The QuestionsPanel header (“Last time, you gave X answers…”) is really the assistant speaking — it belongs in the dialogue stream as bubbles, not as panel chrome.
  • Bubble grouping transforms the visual feel dramatically. Grouped radius with tight spacing makes the conversation feel cohesive. The end bubble in a group gets fully rounded (no tail) — the group shape carries the weight.

🧱 Structure

What did I define?

  • Content directory: content/pods/ikigai/ — self-contained package with screenplay + pod .md files. Later downloadable as a content set.
  • Screenplay format: YAML with copy.* blocks per scene, system.* for metadata messages, timing.* for per-role delay config. Parsed at build time, passed as JS object to the director.
  • DialogueDirector class: methods per scene (firstVisit, returnVisit, boot, resume, answer, completion, close, stageComplete). Returns Emission[] with role, text, variant, and computed delay.
  • Emission type: { role, text, variant, delay } — the director decides everything, the surface just executes.
  • Bubble groupPosition: solo | start | middle | end — computed from the messages array, drives CSS border-radius per role.

⚙️ Decisions

What did I choose (and why)?

  • Screenplay parsed at build time (Astro server) rather than runtime — no YAML parser in the client bundle.
  • Pod type defined in dialogueDirector.ts rather than the Svelte component — avoids circular imports, and the director conceptually owns the pod definition.
  • Completion scene drops “Would you like to continue with another question?” when isLastPod is true — one boolean flag, no if-chain proliferation in the surface.
  • Bubble end position gets fully rounded bottom (no tail) — the group as a whole carries the visual shape.
  • Surface gap reduced from 6px to 3px, bubbleRow margin from 4px to 1px — tight grouping with 18px breathing space on role change.

🔄 Friction

What felt messy or uncomfortable?

  • Circular type import between dialogueDirector.ts and DialogueSurface.svelte caused a silent runtime failure. Svelte components don’t reliably export types to plain .ts files.
  • The opening scene logic (first visit vs return visit vs stage complete) has nested conditions in the reactive block. Works, but it’s the kind of thing the director should own fully in the future.
  • scrollIntoView didn’t work on the surface div — had to use a scroll anchor div at the bottom. The scroll container is the page window, not the surface.
  • The screenplay format has two styles: copy.* blocks (implicitly assistant) and system.* (named keys). A future scenes format with explicit ASSISTANT: / SYSTEM: roles would unify this.

🌱 Learning

What new mental model formed?

  • A screenplay is not code — it’s a creative document that happens to be machine-readable. Timing, copy, and flow structure are all authorial decisions.
  • The director pattern (interpret + emit) is more powerful than a simple config lookup. The director can make decisions (skip lines, choose scenes) based on runtime state while keeping the screenplay declarative.
  • Content sets as directories is the right packaging unit. Everything the director needs to run a content experience lives in one folder.
  • Auto-scroll is a surface concern, timing is a director concern, copy is a screenplay concern. When the boundaries are right, each layer stays simple.

➡️ Next Move

Single clear next step.

  • Director modes: implement Manual (actor chooses via QuestionsPanel) vs Guided (director auto-selects pod with least answers). The screenplay declares the mode, the director enforces it.
  • Scenes format: evolve the screenplay from copy.* / system.* blocks to explicit ASSISTANT: / SYSTEM: lines with stage directions ([SHOW_INPUT], [SHOW_QUESTIONS]).
  • Answer review: completed pods in QuestionsPanel could open an answer review view instead of being dead ends.
  • Restore production budgets: set attention budgets back to 16 before shipping.
  • Meaning Canvas: start the single-column overlay as the next stage after discovery.