# Project Roblox — Journey Page Spec

**Surface:** `https://roblox.stackhousebuilds.com/journey/`
**Purpose:** A live, narrated history of building Roblox games with two 10-year-old twins and AI agents — readable by the twins first, expandable for any parent following along, with one more click for the parent-coders who want to see the actual skills, costs, and artifacts.
**Status:** v1 design, 2026-05-16. Author: HQ + frontend-design skill.

---

## Why this page exists

The standard project surfaces (CHARTER, PLAN, STATE.yaml, decisions-log, GitHub commits) capture **what** happened. They do not capture **the story** in a way a 10-year-old would read, nor in a way another parent could pattern-match against.

The operator wants Project Roblox to double as an **open learning experiment** other parents can mirror. The chat-history metaphor is the carrier: parents already understand text-message threads. If "Dad asked X, AI did Y, here's what shipped" is the spine of every entry, the whole development cycle becomes legible without any framework vocabulary.

This page is the *narrative seam* of the portfolio. The G1 finalist site (the existing `/`) is the *artifact*. The journey page is *how we got there and where we're going*.

---

## Three audiences, one page

Every entry renders in three layers. Default view is the twins layer; the other two open in place on click.

| Layer | Audience | Voice | Length | Default |
|---|---|---|---|---|
| **Twins** | The 10yo boys | Dad-to-kids, plain words, one sentence per speaker turn | ≤2 short sentences per turn | Always visible |
| **Parents** | Any adult following along | Friendly explainer, what phase + what got decided + why | One short paragraph | One click to expand |
| **Tech** | Parent-coders, devs curious about agent orchestration | Skills run, agent IDs, issues, costs, model, files dropped | Compact card with monospace details | Two clicks to expand |

A global **Reading mode** toggle at the top of the page (`Twins · Parents · Tech`) sets the default expansion for every entry at once, so a coder landing fresh can flip to Tech mode and read it like a changelog.

---

## The chat metaphor

Each entry is a short conversation between two speakers:

- **Dad** — the operator. Yellow bubble. Right-aligned. Roblox-fan-site yellow (#FFE066) on ink.
- **Claude** — the AI doing the work. Paper-white bubble. Left-aligned. ⬢ avatar mark.

A third role:

- **The Crew** — used when AI sub-agents do something visible (Researcher, Engineer, Reviewer, Writer). Blue bubble, left-aligned, agent role badge.

Bubbles render in the order the conversation actually happened. Phase headers split the stream like iMessage date dividers — but instead of "Tuesday" they say **PHASE 3 · RANKING**.

### Outcome link (the critical addition)

Every entry that produced an artifact ends with an **outcome chip** — a chunky CTA pointing to where that conversation's output lives on the portal:

> **→ Meet The Five** *(this conversation built the finalist showcase on the homepage)*

This is the connective tissue: chat tells the story, outcome chip drops you on the artifact. As Phases 5–9 land (sales deck, video, etc.), every new entry just adds another outcome chip pointing to whichever page hosts that artifact. The journey grows alongside the site, never replaces it.

---

## Data model

Source of truth: `data/chat-log.yaml` — append-only, human-editable, agent-writable. The page fetches it at runtime via vendored `js-yaml`. Zero build pipeline; saving the file = the page updates on next refresh.

### Entry schema

```yaml
- id: 2026-05-16-phase-3-ranking      # stable slug (date + short verb-phrase)
  date: 2026-05-16T20:06:00Z          # ISO 8601; when the work concluded
  phase: phase_3                       # matches STATE.yaml phase keys
  phase_label: "Phase 3 · Ranking"     # human-readable phase title
  status: done                         # done | active | upcoming
  draft: false                         # true = agent-drafted, not yet operator-skimmed
  turns:
    - role: dad                        # dad | claude | crew
      crew_role: null                  # if role=crew: Researcher | Engineer | Reviewer | Writer
      text:                            # per OD-009: object with three voice layers
        twins:  "Dad asked Claude to pick our top 5 games."
        parent: "Dad asked the AI helper to whittle 57 ideas down to the five we should actually build."
        tech:   "Pick the five we should actually build."
    - role: claude
      text:
        twins:  "Claude scored every idea and picked our best 5!"
        parent: "The AI helper ranked all 57 ideas through the learning-first lens Dad locked in, then a reviewer agent pushed back four times before the tier columns settled."
        tech:   "Ranked all 57 under the LEARNING-first lens. Pet Salon Tycoon, Mystery Mansion, ... Took 4 review rounds to get the tier columns right."
  twins_summary: "Claude scored every idea and picked the best 5 for our family lineup."
  parent_summary: "Engineer ran the ranking matrix under the LEARNING-first rubric the operator locked in OD-002. Reviewer pushed back 4 times until tier columns + a borderline merger were resolved. Output routed to operator INBOX as a G1 hard-gate decision."
  tech_layer:
    skills_run: ["bmad-ranking-matrix"]
    agents: ["HQ Engineer", "HQ Reviewer"]
    issues: ["HQ-396"]
    review_rounds: 4
    artifacts:
      - { label: "research/09-ranking.md", href: "../research/09-ranking.md" }
    duration_min: 180
    cost_usd: 0.40
    models: ["claude-opus-4-7"]
  outcome:                             # optional — only if conversation built a public artifact
    label: "Meet The Five"
    href: "../#finalists"
    summary: "The five finalists are the centerpiece of the homepage."
  tags: ["ranking", "decision-gate"]
```

### Field rules

- `id`: never reused; the page uses it for deep-linking (`#2026-05-16-phase-3-ranking`).
- `status`:
  - `done` — past tense, full styling
  - `active` — current work, animated typing-indicator dots on the last bubble, pulsing accent
  - `upcoming` — ghost styling (dashed border, lower opacity, "expected by" date)
- `draft: true` — entry is agent-drafted but not yet operator-skimmed. Renders with a small `DRAFT` badge so visitors know it may still get edited.
- `outcome` — omit if the conversation didn't produce a public artifact (e.g., an internal decision). Otherwise: link to wherever that work LIVES on the portal, not to the raw artifact path. Prefer section anchors on the homepage over raw `.md` files.
- `tags` — used by the filter chips at the top of the page. Standard tags: `research`, `brainstorm`, `ranking`, `decision-gate`, `ship`, `build`, `voice`, `video`, `meta`.
- `turns[].text` — **OD-009 mandatory shape**: object with `twins`, `parent`, and `tech` string keys. The Reading-mode toggle picks which one renders in the bubble. Bare string is back-compat only (treated as `tech` with a draft placeholder shown in Twins+Parents modes) and is rejected by `voice_canon_lint` — it will block your commit until rewritten.

### Per-layer voice rules (OD-009)

Each `turns[].text.{twins,parent}` and each `twins_summary` / `parent_summary` is enforced by `tools/voice_canon_lint.py` against `tools/voice_canon_rules.yaml`. See `../COPY-VOICE.md` for the narrative spec (banned words, exemplars, pre-publish checklist). The lint runs:

1. **Inside the `hq-journey-entry` skill** — the skill refuses to mark its issue done if its draft entry fails.
2. **In the project git pre-commit hook** — staged edits to `chat-log.yaml` or `site/**/*.html` are scanned; a failure aborts the commit. (Operator can bypass with `--no-verify` for genuine emergencies, but the lint exists precisely so that bypass becomes the rare exception.)

`tech_layer.*` and `turns[].text.tech` get no banned-word lint — the receipts layer is meant to carry raw operator-voice (issue IDs, agent IDs, model names, OD/HQ numbers).

---

## Page structure

```
┌─────────────────────────────────────────────────┐
│ TOPBAR (shared with /)                          │
│ ⬢ PROJECT ROBLOX   Home · Journey · ...         │
├─────────────────────────────────────────────────┤
│ HERO                                            │
│   "The Journey"                                 │
│   Subtitle: what this page is, in one breath    │
│   Stat strip: phases done · days in · ships     │
├─────────────────────────────────────────────────┤
│ ONBOARDING CARD (sticky-dismissable for the     │
│ first visit; explains 3-layer disclosure +      │
│ chat metaphor)                                  │
├─────────────────────────────────────────────────┤
│ STICKY CONTROL BAR                              │
│   Reading mode: [Twins] [Parents] [Tech]        │
│   Filter:       [All] [Research] [Decisions] …  │
├─────────────────────────────────────────────────┤
│ CHAT STREAM (chrono top-down)                   │
│                                                 │
│   ── PHASE 0 · KICKOFF · 2026-05-16 ──          │
│   [dad bubble]  [claude bubble]                 │
│   → outcome chip                                │
│                                                 │
│   ── PHASE 1 · RESEARCH · 2026-05-16 ──         │
│   [dad bubble]  [crew:Researcher × 7]           │
│   [crew:Reviewer]                               │
│   → outcome chip                                │
│   ...                                           │
│                                                 │
│   ── PHASE 4 · BUILD-OUT · ACTIVE ──            │
│   [dad bubble]  [crew × N, last with typing…]   │
├─────────────────────────────────────────────────┤
│ WHAT'S NEXT (ghost bubbles)                     │
│   Phase 5 · Mini-site polish                    │
│   Phase 7 · Video pre-prod                      │
│   Phase 8 · Video render                        │
├─────────────────────────────────────────────────┤
│ FOLLOWING ALONG? (parent CTA)                   │
│   "Mirror this with your own kids"              │
│   5-step quick-start + invitation to fork       │
├─────────────────────────────────────────────────┤
│ FOOTER (last-updated stamp, links to CHARTER,   │
│ STATE, this spec)                               │
└─────────────────────────────────────────────────┘
```

**Scroll behaviour:** page loads chronologically from top. A floating "Jump to today" button anchors to the most recent active/done entry. First-time visitors see the onboarding card; localStorage dismissal hides it on return.

---

## Visual system

Inherits the existing site (`assets/styles.css`) completely. Same fonts, same palette, same blocky shadows. The journey page is a *chapter of the same publication*, not a parallel aesthetic.

Specifically reused:
- `--bg`, `--bg-mid`, `--bg-soft` — dark navy + gradient mesh
- `--ink`, `--paper`, `--paper-soft` — text + bubble surfaces
- `--rb-yellow`, `--rb-blue`, `--rb-pink`, `--rb-green`, `--rb-orange`, `--rb-purple` — accent palette
- `--font-display` (Lilita One), `--font-body` (Fredoka) — already loaded via Google Fonts import
- `--shadow-block`, `--shadow-lift` — chunky 4px/8px offset shadows
- `--radius-card`, `--radius-pill`

New in `journey.css`:
- `.bubble` (base) + `.bubble.dad` (yellow, right) + `.bubble.claude` (paper, left) + `.bubble.crew` (blue, left, role badge)
- `.phase-divider` — chunky display-font header in yellow, full-width line break
- `.entry` — clusters the bubbles + outcome chip + disclosure controls + tech panel
- `.disclosure-trigger` (mini button) + `.layer.parent` + `.layer.tech` (collapsible panels)
- `.outcome-chip` — chunky button styled like an `.is-yellow` chip from the existing system, oversized
- `.ghost` — dashed border, 0.55 opacity, used for `status: upcoming`
- `.typing-dot` — 3-dot pulse used on `status: active` last bubble

---

## Self-maintenance — how the log keeps itself current

A new HQ skill, `hq-journey-entry`, runs at meaningful project events and drafts new entries.

### Triggers

Any of:
1. **Phase open/close** — when STATE.yaml transitions (e.g., `phase_3` → `g1_gate` → `phase_4`), fire one closing entry for the phase that ended.
2. **Operator decision** — when a new `OD-NNN` lands in STATE.yaml `operator_decisions[]`, fire one entry describing the call.
3. **Ship event** — when a Phase 5/6/7/8 artifact goes public (mini-site update, deck published, video rendered), fire one entry pointing to it.
4. **Manual** — operator can fire `/hq-journey-entry "<short prompt>"` for one-off moments worth narrating (e.g., today's public URL launch).
5. **Nightly catch-up** — cron compares STATE.yaml + decisions-log diff against last entry's `date`. If something material happened that no entry covered, draft one.

### Process inside the skill

1. Read `STATE.yaml`, `decisions-log.md`, recent closed HQ issues, recent commits in `_hq/projects/project-roblox/`.
2. Identify the *one* meaningful event since the last entry.
3. Draft a 2–4 turn conversation (dad + claude/crew) capturing the essence.
4. Write the twins summary, parent summary, and tech layer.
5. Pick the right outcome link (lookup table: phase → portal anchor).
6. Append to `data/chat-log.yaml` with `draft: true`.
7. Post a one-line to `INBOX.md`: `2026-05-NN HH:MM UTC — project-roblox — JOURNEY DRAFT: <id> — operator skim before promoting`.

### Operator weekly skim (5 min)

1. Open `data/chat-log.yaml`, filter `draft: true`.
2. Edit if voice is off; flip `draft: false`.
3. Next page load reflects the change. No deploy step.

### Outcome-link lookup table

| Phase event | Outcome label | href |
|---|---|---|
| Charter signed | View the charter | `../CHARTER.md` (or `/charter/` if turned into a page) |
| Phase 1 research bundle landed | Open the research room | `../research/` (or `/research/` if turned into a browsable index) |
| Phase 2 brainstorm published | Browse all 57 ideas | `../research/08-brainstorm-raw-ideas.md` |
| Phase 3 ranking final | Meet The Five | `../#finalists` |
| G1 signed | See the decision pack | `../#decision` |
| Phase 5 mini-site update | (none — this IS the site) | — |
| Phase 6 sales deck published | View the pitch deck | `../deck/` (when built) |
| Phase 7 storyboard | Read the storyboard | `../video/storyboard.md` (when built) |
| Phase 8 video shipped | Watch the commercial | `../video/` (when built) |
| Phase 9 closure | Closing note | `../CLOSURE.md` (when written) |

Operator may override the link per-entry; lookup is just the sensible default.

---

## Following-along resource for other parents

The bottom-of-page CTA invites parents to mirror the process. It is intentionally **not prescriptive** — the user wants other families to make this their own. The CTA links to:

1. **The "fork this" appendix** (this file's last section) — a 5-step quick-start that doesn't require BMAD or Paperclip.
2. **The charter** — for those who want to see the full original prompt.
3. **The plan** — for those who want to see the phase board.

### Fork-this 5-step (for other parents)

1. **Sit down with your kid** and ask what game(s) they wish existed. Write down everything they say.
2. **Ask Claude (or any AI) to research the platform** — what's hot, what monetizes, what tools exist. Don't filter early; ranking comes later.
3. **Brainstorm wide** — 40+ ideas. Use the AI as a creative partner, not a filter.
4. **Rank under YOUR family's lens.** Ours is LEARNING-first; yours might be playability-first or art-first. The rubric is the most important decision you'll make.
5. **Pick a small number to actually build** (we picked 5; you might pick 1 to start). Document everything as you go — your kids will want to look back.

This list is a starting point, not a manual. The journey page is the proof that this works; the steps above are the seed pattern others can adapt.

---

## Open questions for v2

- **Search**: should the chat be searchable? (deferred — under 50 entries probably not needed)
- **Comments / reactions**: can the twins react to entries with an emoji that the page shows? (deferred — needs a write API)
- **Per-entry permalinks shared on social**: open-graph cards for individual chat entries? (deferred — until project ships publicly)
- **Sub-conversations**: when an entry has lots of detail, should it expand into a nested "side conversation" thread instead of just a tech panel? (deferred — ship v1 flat, see if the need surfaces)
- **Video embeds**: when Phase 8 ships, the entry that points to the video should probably embed it inline, not just link. (Phase 8-time decision.)

---

## v1 success criteria

- [ ] Page loads cleanly on https://roblox.stackhousebuilds.com/journey/
- [ ] 10+ seed entries render covering Phase 0 → Phase 4
- [ ] Three-layer disclosure works (per-entry expand + global reading-mode toggle)
- [ ] Filter chips work
- [ ] Every entry with a public outcome has a clickable chip pointing to the right place on `/`
- [ ] Upcoming/ghost entries visibly differ from done entries
- [ ] Lighthouse desktop ≥ 0.85 (matches hq-cockpit-v2 standard)
- [ ] Visual cohesion with existing site — passes 5-second "is this the same site?" test
- [ ] Mobile-readable (twins will check on their iPads)
- [ ] No build step; edit YAML → next page load shows it
