Design Journal — The Meaning Canvas (First Pass)


🎯 Intent

What was I trying to achieve today?

  • Build the first working version of the Meaning Canvas — an overlay that shows all answers grouped by pod in a multi-column layout.
  • Keep it content-agnostic: works for ikigai (4 columns), mini-proposal (6 columns), or any future content set.
  • Wire it into the dialogue flow via a floating action button so the actor can review their answers at any point.
  • Follow the chunked approach from earlier planning: start with the overlay shell + column grouping + answer cards as a single deliverable.

🧭 Guiding Questions

What questions are shaping my thinking right now?

  • What’s the right entry point for the canvas — a FAB, a stage direction, or both?
  • Should the canvas be a separate route or an overlay on top of the dialogue? Overlay keeps context, route gives more room.
  • How does this scale when a pod has 16 answers? Does it need collapse/scroll within a column?
  • What role do tags play — are they per-answer metadata the actor adds, or auto-derived from the pod category?
  • Is the canvas read-only, or should the actor be able to edit/delete answers from here?

🧠 Insight

What clicked?

  • The canvas is fundamentally a different mode of seeing the same data. The dialogue is temporal (one answer at a time, in sequence). The canvas is spatial (all answers at once, grouped by theme). Both views compound — the dialogue generates meaning, the canvas reveals patterns.
  • Keeping MeaningCanvas as a pure presentational component (pods + allAnswers in, close event out) means it doesn’t care about the dialogue engine at all. It just renders what’s in the answer store.
  • The overlay pattern (backdrop + panel) feels right for now. It’s a pause from the conversation, not a departure. Escape and backdrop click to dismiss keep it lightweight.
  • Mobile stacking (columns go vertical under 640px) is the obvious responsive move and works naturally with the flex layout.

🧱 Structure

What did I define?

  • MeaningCanvas.svelte: Overlay component. Takes pods[] and allAnswers[] as props. Groups answers by questionId matching each pod. Renders one column per pod with title, category label, and answer cards.
  • Answer cards: Text + optional colored pill tag. Tags use data-tag attribute for per-category color (passion = pink, skill = blue, need = green, paid = gold).
  • Header: Back arrow (← Meaning Canvas) on the left, centered title, close button (✕) on the right. Matches the UI sketch layout.
  • Footer: “Entries stored locally on this device” — privacy signal, keeps expectations clear.
  • FAB trigger: “Canvas” button fixed to bottom-right alongside “Resume later”. Both use the same pill-shaped FAB style with backdrop blur.
  • Integration: showCanvas boolean in DialogueController toggles the overlay. Canvas receives the active content set’s pods and all answers.

⚙️ Decisions

What did I choose (and why)?

  • Overlay, not route — The canvas is a lens on the current content set, not a destination. Keeping it as an overlay means the actor stays in the dialogue context and can dismiss quickly.
  • FAB as entry point — Simple and always available. A stage direction ([SHOW_ANSWERS]) can come later as a director-triggered entry, but the FAB gives the actor agency to review whenever they want.
  • No export yet — The UI sketch shows an “Export JSON” button. Skipped for now — the canvas needs to prove its value as a review tool first before adding data portability.
  • Tag colors hardcoded to ikigai categories — Pragmatic shortcut. The tag system needs to become content-driven (defined in screenplay or pod frontmatter) rather than hardcoded CSS selectors. Good enough for now, but this is technical debt.
  • Answers sorted by createdAt — Chronological within each column. The actor sees their journey of thought, earliest to latest.

🔄 Friction

What felt messy or uncomfortable?

  • The FAB positioning is manual (right: 130px for canvas, right: 18px for resume). Two fixed buttons side by side works for now but doesn’t scale if more actions appear. A proper action bar or bottom sheet would be cleaner.
  • Tag colors are hardcoded to four ikigai categories (passion, skill, need, paid). Any new content set with different categories would need new CSS. This should be driven by content configuration.
  • The title in the header is absolutely positioned (left: 50%; transform: translateX(-50%)). Works visually but fragile — long titles or translated text could overlap the buttons.
  • No empty state for the canvas as a whole — if no answers exist at all, you get four columns of “No entries yet” which isn’t very helpful. Could show a message like “Start answering to see your canvas take shape.”

🌱 Learning

What new mental model formed?

  • The dialogue and the canvas are two projections of the same underlying data. The dialogue is a process (sequential, time-bound). The canvas is a product (spatial, persistent). Good tools let you move fluidly between process and product views.
  • Starting with the overlay shell as a single deliverable was the right chunk size. It’s immediately useful (you can review your answers) and creates the scaffolding for everything else (inline columns, export, editing).
  • The pods + allAnswers prop interface is the right abstraction boundary. The canvas doesn’t need to know about screenplays, directors, or dialogue state. It just needs the content structure and the actor’s data.

➡️ Next Move

Single clear next step.

  • Content-driven tag colors: Move tag definitions into pod frontmatter or the screenplay so any content set can define its own color palette.
  • Canvas empty state: Show a meaningful message when no answers exist instead of N columns of “No entries yet.”
  • Inline column mode: Reuse the column component to show a single pod’s answers inline in the dialogue (triggered by [SHOW_ANSWERS] stage direction after completion).
  • Export: Add JSON export from the canvas footer — the actor’s data is theirs to keep.
  • Column scroll: Test with 16 answers per pod and decide if columns need internal scroll or collapse.