gray-matter eagerly loads Node's Buffer API path even when only
matter(rawString) is called, crashing browser bundles. Replace it with
an inline frontmatter parser backed by the browser-safe yaml package.
All 84 mystery tests pass; build is clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rooms, items, and endings now come from .md files under world/{rooms,items,endings}/.
Encounters still come from encounters.ts (Tasks 11–12 will complete that leg).
Cross-reference validation at module init ensures exits, item refs, and encounter
refs are all consistent. Deletes rooms.ts, items.ts, roundtrip.test.ts, and the
one-shot migration script (whose output is already committed).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds scripts/migrate-mystery-content.ts which reads rooms, items,
encounters, and endings from TypeScript source and emits byte-identical
markdown files under src/mystery/world/{rooms,items,encounters,endings}/.
Installs tsx as a devDep to support .ts imports across src/ during the
one-shot run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
14-task plan covering: gray-matter+zod setup, schemas, four pure
parsers (room/item/ending/encounter), narration() helper with
auto-registration, one-shot migration script, round-trip
verification, world assembly cutover, encounters.ts refactor,
manual playthrough, and Obsidian vault config.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Address spec review feedback: switch frontmatter convention from snake_case
to camelCase to match existing TS field names; surface the working
three-room prototype as the explicit deliverable; rephrase the Astro
content collections out-of-scope item to clarify the import.meta.glob
choice is a tooling decision, not a feature exclusion.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move rooms, items, encounter narration, and endings from TypeScript
object literals to markdown files editable in Obsidian. Engine code,
tests, and the World shape are unchanged. Tonal refinement is a
separate spec that follows.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
appendLines() only updated the DOM, never state.transcript, so any
UI-originated line (player input, restart/undo/quit messages) vanished
on page reload. Engine narration was unaffected because dispatch()
already adds its lines to state.transcript.
Fix: appendLines() now pushes into state.transcript (capped at
TRANSCRIPT_CAP) and renders. Engine output uses renderAll() directly
since dispatch already added its lines to state.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Captures the final code reviewer's recommendations: hard prerequisites
(read/light/extinguish/use verbs; disambiguation; endedWith ending screen),
should-fix items (look-at parser polish, theme-state divergence, roomState
type lie), and a polish backlog. Read this before generating the next plan.
Pure computeChips function (TDD, 4 tests) generates context-aware direction/item/encounter/meta chips from game state; chip-render.ts wires chips to DOM; terminal.ts calls refreshChips on init, each Enter dispatch, restart, and undo.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gothic mystery, M-scope (18-22 rooms), authored TypeScript engine,
no LLM at runtime, fullscreen CRT terminal at /mystery, two themes
(amber + ANSI), context-aware mobile chips, auto-save to localStorage.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>