Scaffold Kissaten Yugure; add M2 day spine, plan and script

Stage 1 (shop scene, customer, siphon brew minigame, serve loop) and the
M2 day spine: day counter, three-phase day, event-driven clock, journal
line, and a SaveState with magic/version/checksum.

Saving to disk is NOT working yet. A cartridge ROM can reach the Disk ROM
only from RAM (both PHYDIO and CALSLT switch page 1 out from under the
caller), and ROMDelayBoot is required so the Disk ROM's INIT runs at all.
With both in place the disk is detected, but sector I/O returns carry-clear
without transferring — proven with a sentinel. Probe now verifies the
buffer actually changed, so a non-working disk degrades to "no save"
rather than corrupting anything. Full findings in the project CLAUDE.md.

Also documented: keyboard reads need interrupt protection (the BIOS ISR
scans the matrix too), and BankedCall must stay off until banked data
exists.

Docs: PLAN.md (ten milestones, per-stage requirements, decision queue),
SCRIPT.md (all four character arcs, 60 beats, checked against the
26-character box), and amendment notes in DESIGN.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 21:58:22 +02:00
co-authored by Claude Opus 5
parent 4c33bdb880
commit 45749775fa
12 changed files with 3071 additions and 0 deletions
@@ -0,0 +1,115 @@
# Design conversation record — Kissaten Yūgure
A record of the original brainstorm and design discussion (Claude ↔ Jurjen,
July 2026) that led to this project. Kept for rationale and context; the
distilled result lives in `DESIGN.md`.
---
## 1. The brief
Jurjen wanted a new MSX2 game idea: **a cozy game targeted mainly at male
adults who love Japanese art and retro games**, built with MSXgl.
Claude's read on the audience: nostalgia for late-80s Japan, quiet melancholy,
craftsmanship, and pixel art in the style of MSX magazine covers / Konami and
Compile titles. The MSX2 itself is a Japanese cultural artifact, so the
platform is part of the appeal. Reference vibe: *A Short Hike* energy,
rendered like an MSX2 classic.
## 2. Four concepts pitched
1. **Showa-era shopkeeper sim** — run a tiny kissaten, sento, or ramen stall
in a sleepy 1980s town. Regulars with small stories, seasons change the
palette (SCREEN 5 palette swaps per season = big atmosphere, low cost).
Simple state machines + dialogue, MSXgl-friendly; PSG/NDP pipeline fits
gentle city-pop-adjacent loops. Hits the demographic dead center.
2. **Bonsai / garden tending game** — shape a tree or karesansui garden over
in-game years via a simple L-system-ish growth model. Minimal input,
maximal zen, sumi-e visuals, persistent growth via save. Smallest and most
distinctive option; nobody has made it on MSX.
3. **Rural train journey game** — conductor/passenger on a one-car local
line; each station is a vignette. Landscapes are the star, but horizontal
scrolling is work on MSX2 (vertical scroll register is free), so it would
need screen-by-screen scenes or parallax-lite. Densha + inaka nostalgia.
4. **Yokai postman / errand game** — cozy-spooky letter delivery between
friendly yokai at dusk. Iconic character material, light fetch-quest
structure, Ghibli / Mizuki Shigeru vibe.
**Recommendation:** #1 or #2, because scope kills hobby projects. #1 had the
strongest emotional hook and marketing appeal ("run a coffee shop on real
MSX2 hardware"); #2 was the most achievable and distinctive.
**Cross-cutting principles:** lean into palette work (MSX2's superpower),
keep text minimal or bilingual-friendly for the Japanese retro community,
and let the MML → NDP music pipeline carry the mood.
## 3. Decision
Jurjen picked **#1, the kissaten sim**. Working title: **Kissaten Yūgure**
("Twilight Coffee Shop") — you inherit a small kissaten in a fictional
provincial town, 1987.
## 4. Design deep-dive (summary — full detail in DESIGN.md)
- **Core loop:** one day ≈ 510 real minutes. Morning prep (menu focus,
radio weather, stock) → open hours (serve + siphon-brew timing minigame +
dialogue with regulars) → evening close (till, journal, save).
- **Cozy contract:** no fail states, no bankruptcy; money gates cosmetic and
menu upgrades (grinder, jazz records, a cat). Progression = story + seasons.
- **Regulars:** 68 characters (retired stationmaster, exam student, manga
artist, widow...), each with 1220 short scenes triggered by day count,
season, weather, or what you serve. Right order at the right moment
advances arcs.
- **Screen layout (SCREEN 5, 256×212):** 16 px status bar (day/season,
clock, ¥) · 132 px shop scene (door, counter with customer sprites,
siphon rig) · 64 px dialogue window (48×48 portrait, 3 lines × 26 chars,
typewriter reveal). Static-heavy on purpose: only sprites move — no
scrolling — the biggest scope-saver in the design.
- **Hardware mapping:** VRAM page 0 = scene bitmap, page 1 = asset warehouse
blitted via HMMM/HMMV. Seasonal palette trick: one background authored
around palette slots (sky in 811, wood tones in 47); each season/time of
day is a 32-byte palette table, optionally lerped across the day. Sprite
mode 2, two layered 16×16 sprites per customer. Portraits 48×48 × 3
expressions — where the pixel-art budget goes.
- **Data model:** tiny `SaveState` (~40 bytes) with day, season, weather,
money, unlock bitmask, and 8 `Regular` structs (arc_stage, affinity,
last_visit_day). Dialogue as data: YAML/JSON compiled by a Node.js tool to
C arrays / binary banks. ASCII16 MegaROM layout from day one.
- **Visitor logic:** weighted table per tick, filtered by season / weather /
time / days-since-last-visit — tunable in a spreadsheet, produces
noticeable patterns ("the stationmaster always comes when it rains").
- **Music:** 68 short cozy PSG loops via the existing MML → NDP →
`ndp_player` pipeline (`generate_mml.js` for AI-assisted MML). Diegetic
jukebox upgrade lets the player pick the shop's track.
- **Scope ladder:** (1) scene + one customer + brew + serve → (2) day cycle
+ save + money → (3) dialogue engine + two regulars ← real milestone →
(4) seasons/weather/palettes → (5) full cast, upgrades, endings. Every
stage playable.
## 5. Moving to Claude Desktop / Claude Code
Jurjen asked about continuing the project in Claude Desktop with context
files. Plan:
- Put a lean **CLAUDE.md** in the project root — Claude Code reads it at the
start of every session. It holds build commands, toolchain quirks (SDCC,
MSXgl paths, openMSX), conventions, and design pillars; kept under ~200
lines, referencing deeper docs instead of duplicating them.
- Full design lives in **docs/DESIGN.md**; this file (**CONVERSATION.md**)
preserves the original discussion and rationale.
- Claude Code's auto memory will additionally accumulate learned corrections
(e.g. bank layout details) over time.
- The dialogue compiler (`compile_dialogue.js`) will live in `tools/` next to
the existing `generate_mml.js`.
## 6. Open threads (not yet designed)
- Dialogue script format spec + compiler implementation
- Brew minigame detailed design
- Palette / day-cycle system implementation details
- Character roster finalization and story arcs
- Bank layout plan for the ASCII16 MegaROM
+175
View File
@@ -0,0 +1,175 @@
# Kissaten Yūgure — Design document
Working title: **Kissaten Yūgure** ("Twilight Coffee Shop")
Platform: MSX2 · Library: MSXgl (C) · ROM: ASCII16 MegaROM
> **Amendments.** This document still describes the game's intent and is the
> place to start. A few specifics have since been decided differently — where
> they conflict, the documents below win:
>
> - **Cast size: four, not six to eight** (§3). The four examples in §3 became
> the entire roster. Rationale in `PLAN.md` §6; full arcs in `SCRIPT.md`.
> - **Endings: one**, not several (§8 stage 5). `PLAN.md` §6.
> - **Saving: a real save disk** (`.dsk`), not yet working — see the disk
> section in `../CLAUDE.md`. Note the RP-5C01 CMOS holds only 6 bytes
> through MSXgl, so it is not an alternative for a ~40-byte `SaveState`.
> - **Music (§7) is out of date.** It describes a PSG / MML → NDP pipeline;
> the working pipeline is `msx-music-generator` → lVGM + ayFX. Which chip
> this game targets is still open — `PLAN.md` §8 item 15.
> - **The brew minigame is coffee-only.** Aki's cream soda is poured, not
> brewed, so her visits skip it — `SCRIPT.md` §8.
>
> Build order and per-stage requirements live in `PLAN.md`, which supersedes
> the scope ladder in §8 below with a finer ten-milestone breakdown.
## 1. Concept
You inherit a small kissaten (coffee shop) in a fictional provincial Japanese
town in 1987. A cozy, no-fail-state game about serving regulars, learning
their stories, and watching the town and seasons change.
**Audience:** adult retro gamers with a love of Japanese art, computers, and
late-80s Japan nostalgia. The MSX2 itself is part of the fantasy — the game
should look like it came off an MSX magazine cover.
**Tone references:** A Short Hike (pace and warmth), Konami/Compile-era MSX2
pixel art, Showa-era kissaten culture, gentle city-pop-adjacent PSG music.
**The cozy contract:** no fail states. You cannot go bankrupt. Money gates
cosmetic and menu upgrades (better grinder, jazz records, a cat), not
survival. Progression = unlocking regulars' stories and seasonal change.
## 2. Core loop
One in-game day ≈ 510 real minutes, in three phases:
1. **Morning (prep):** choose today's menu focus (coffee blend, toast set,
curry), check the radio for weather (weather affects who visits), buy stock.
2. **Open hours (the heart):** customers arrive one or two at a time. Take
orders, brew/cook via a timing minigame, and — most importantly — talk.
Regulars have multi-day story arcs told in short dialogue beats.
3. **Evening (close):** count the till, journal entry summarizing the day, save.
**Brew minigame:** a siphon coffee brew with a "release at the right moment"
mechanic. One-button friendly, thematic, satisfying to master. Quality result
feeds into customer affinity slightly (never punishingly).
## 3. The regulars
Six to eight recurring characters; this is where the game lives. Examples:
- The retired stationmaster
- A high-schooler studying for entrance exams
- A manga artist missing deadlines
- A widow who orders the same thing daily
Each has a story arc of ~1220 short scenes, triggered by day count, season,
weather, or what you serve them. Serving the *right* thing at the right moment
advances arcs — the player learns preferences by paying attention, which
mechanically rewards the "regulars at my shop" fantasy.
**Visitor logic per open-hours tick:** roll against a weighted table filtered
by (season, weather, time-of-day, days-since-last-visit). Simple, tunable in
a spreadsheet, and it naturally produces patterns players notice and love
("the stationmaster always comes when it rains").
## 4. Screen layout — SCREEN 5 (256×212)
| Region | Height | Contents |
|---|---|---|
| Status bar | 16 px | Day + season · clock · money (¥) |
| Shop scene | 132 px | Tile/bitmap background: window, shelves, radio. Door zone (customer entry), counter zone (16×16 layered customer sprites), siphon rig zone (brew minigame). |
| Dialogue window | 64 px | 48×48 portrait left; 3 lines × 26 chars text with typewriter reveal; choice cursor on line 3 when needed. |
Deliberately static-heavy: only sprites move, so the MSX2's weak scrolling is
sidestepped entirely. Status bar and dialogue window redraw rarely — only the
scene needs per-frame attention. This is the single biggest scope-saver.
## 5. Hardware / MSXgl mapping
**Video.** SCREEN 5 (G4), 16 colors from 512.
- VRAM page 0: visible shop background bitmap.
- VRAM page 1: asset warehouse — customer sprite frames, portraits, UI tiles,
blitted with VDP commands (HMMM); dialogue box open/close is HMMV rectangle
fill + font rendering, never touching the scene.
**Seasonal palette trick.** Author the background once, designed around
palette slots: sky-through-window colors in slots 811, wood/warm tones in
47. Each season *and* time of day is then just a 32-byte palette table —
morning spring light vs. rainy autumn dusk on the same bitmap, basically
free. Optionally lerp between palettes across the in-game day for a slow
ambient shift. This is the most atmospheric feature in the game.
**Sprites.** Sprite mode 2 (per-line colors on 16×16). Two layered sprites
per customer (outline + fill) for the classic MSX2 look. Max two customers
on screen plus player hands/steam effects — nowhere near the 8-per-line limit.
**Portraits.** 48×48 with three expressions per character (neutral, happy,
troubled), copied from page 1 into the dialogue box. Portraits are where the
pixel-art budget goes; they sell the characters.
**ROM.** ASCII16 MegaROM from day one — dialogue, portraits, and music banks
will not fit in 32KB. MSXgl supports banked ROMs well.
## 6. Data model
```c
typedef struct {
u8 id;
u8 arc_stage; // progress through their story
u8 affinity; // 0-255, raised by right orders
u8 last_visit_day;
} Regular;
typedef struct {
u16 day;
u8 season; // derives palette set
u8 weather; // affects visitor table
u16 money;
u8 unlocked_items; // bitmask: grinder, records, cat...
Regular regulars[8];
} SaveState; // ~40 bytes → trivial to save
```
**Dialogue** is the biggest data mass. Scenes stored in a flat script format:
```
(trigger conditions) → (portrait id, expression, text lines,
optional choice, effects)
```
Authored in YAML/JSON; a small Node.js compiler (`tools/compile_dialogue.js`)
emits C arrays or a binary blob for a MegaROM bank. Budget: ~8 characters ×
~15 scenes plus ambient lines.
## 7. Music
PSG via the MML → NDP compiler → `ndp_player` pipeline, with AI-assisted MML
generation through `tools/generate_mml.js` (Anthropic API).
Needs: 68 short cozy loops rather than driving action tracks — morning,
afternoon, evening, rain, plus one theme per major story beat.
**Diegetic jukebox:** the record-player upgrade lets the player choose the
shop's background track — a feature and a home for all generated music in one.
## 8. Scope ladder
Build in this order so every stage is a playable game:
1. Shop scene + one customer + brew minigame + serve loop, no story
2. Day/night + save + money
3. Dialogue engine + two regulars with short arcs ← **the real milestone**
4. Seasons/weather/palettes
5. Remaining cast, upgrades, endings
If serving the exam student his usual and getting one new line of his story
feels good at stage 3, the game works.
## 9. Other principles
- Lean hard into palette work — the MSX2's superpower.
- Keep text minimal or bilingual-friendly; the Japanese retro community is a
big chunk of the real audience.
- Let the soundtrack carry the mood — cozy games live or die on music.
- Marketing hook: "run a coffee shop on real MSX2 hardware."
+518
View File
@@ -0,0 +1,518 @@
# Kissaten Yūgure — Production plan
Companion to `DESIGN.md` (what the game is) and `CONVERSATION.md` (why).
This document is **how it gets built**: milestone order, the cast, the story
architecture, and what has been deliberately cut.
Status at time of writing: **M1 complete** (scope ladder stage 1).
---
## 1. Organizing principle
The code in this project is small. Stage 1 — shop scene, customer, brew
minigame, full serve loop — took one sitting and fits in 17KB of a 128KB ROM.
Every remaining *system* is comparably small.
The risk is content. Four characters with real arcs is roughly 60 scenes of
writing and 12 portraits of pixel art. The failure mode for a project like
this is producing all of that before discovering the core moment doesn't land.
So the plan is ordered by one rule:
> **Reach the emotional test on the least content possible, then build the
> machinery around what you learned.**
`DESIGN.md` §8 states the test directly: *if serving the exam student his
usual and getting one new line of his story feels good, the game works.*
Everything before M3 exists only to make that test possible. Everything after
M3 is scaling something already proven.
---
## 2. Milestones
Each milestone has an exit criterion. Don't advance without meeting it.
Each also lists **what it requires** — split into what I need *from you*
(decisions, writing, art) and what must be *in place* technically. Anything
under "from you" is a hard block: I can't guess my way past it, and guessing
wrong is expensive to unwind later.
### M1 — Serve loop ✅ *(complete)*
Shop scene, one customer, siphon brew minigame, serve loop, no story.
**Exit:** ✅ A customer arrives, orders, is served a brew of variable quality,
reacts, and leaves; the counter increments and the next arrives.
### M2 — The day spine
The thin half of scope-ladder stage 2. Day counter, three phase transitions
(morning prep → open hours → evening close), save/restore, clock and day in
the status bar.
Money is deliberately **not** built here beyond a displayed number. It gates
nothing until M9, and a value that gates nothing isn't worth debugging yet.
This milestone exists because the day counter is the spine every dialogue
trigger hangs from — arc pacing, `last_visit_day`, "he always comes when it
rains" patterns.
**Requires — from you:**
- **Save medium.** My recommendation: **RTC CMOS**. Every MSX2 has it, it
holds ~50 bytes, the `SaveState` in `DESIGN.md` §6 is ~40, and
`msxgl_config.h` already enables `RTC_USE_SAVEDATA` + `RTC_USE_SAVESIGNED`.
Alternatives are cartridge SRAM (needs mapper support, better capacity) or
the FM-PAC's SRAM (needs the cartridge present). Say the word if you'd
rather not depend on CMOS.
- **Day length.** `DESIGN.md` says 510 real minutes. I need one number to
tune against, plus a rough customers-per-day count (I'd start at 46).
- **Clock model:** does time advance in real seconds, or one tick per customer
served? Event-driven is more forgiving of a player who walks away — which
suits the cozy contract — and it's what I'd pick.
**Requires — in place:** nothing beyond M1.
**Produces:** `SaveState` struct, phase state machine, save/load module.
**Status:** day counter, three phases, journal line and `SaveState` are done
and playable. **Persistence is blocked** — sector I/O from a cartridge ROM
reports success without transferring data; full findings in the disk section
of `../CLAUDE.md`.
**Pacing dial, revisited at the end.** `CUSTOMERS_PER_DAY` in `kissaten.c` is
the only number that sets day length. Worth reconsidering at M10 as a
player-facing choice — offered once at first boot ("how long should a day
be?"), or as a shelf option alongside the records. A game with no fail states
can afford to let the player set its own tempo, and it costs one saved byte.
Not worth building before the content exists: the right default only becomes
obvious once days have stories in them.
### M3 — Vertical slice ← **the milestone that matters**
One regular. Six beats. **Hardcoded in C.** No YAML, no compiler, no engine,
no data format.
Build the exam student (§3 below) because their arc is the most legible: the
"usual" is visually distinct (cream soda, not coffee), the want is stated
early, and the change is a single order switch the player can *see*.
Also needed: order recognition — the customer asks for something specific, and
serving it (vs. not) advances or holds the arc.
**Requires — from you:**
- **Aki's six beats, as written text.** 6 × 3 lines × 26 chars. This is the
hard block on M3 — there is no version of this milestone without it. Either
you write them, or you tell me to draft them and review. If I draft: I need
a tone sample you like (a scene from a game or book that hits the register
you want) so the first pass isn't a guess.
- **The item list at this point.** Minimum coffee + cream soda, but tell me if
the toast set or curry from `DESIGN.md` §2 should exist yet.
- **A scratch portrait for Aki — 48×48, three expressions.** Crude is fine;
ugly is fine. But M3's exit criterion is an *emotional* judgement, and
judging it with a blank brown rectangle where a face belongs stacks the deck
against the test. This is the one place art work moves earlier than M6, and
it's worth it.
**Requires — in place:** M2's day counter (arc beats are paced by day).
**Produces:** hardcoded arc, order-recognition logic, "the usual" concept.
**Exit:** The `DESIGN.md` test. Serve the student their usual, get the next
beat of their story, and want to come back tomorrow to see the following one.
If this is flat, stop and fix the *writing*, not the code.
### M4 — Dialogue engine and compiler
Now — and only now — extract the engine from what M3 taught. Scene data model,
trigger evaluation, `tools/compile_dialogue.js` emitting a binary bank, and
`BankedCall = true` re-enabled (see §7 hazards).
Port the student's hardcoded arc to data and prove it plays identically.
**Requires — from you:**
- **Sign-off on the scene schema before I write the compiler.** I'll propose
the YAML shape as a one-page sample; reviewing it costs ten minutes and
changing it after 60 scenes are authored costs a rewrite.
- **The string-ID decision** from §4 — whether to route text through IDs now
for a possible Japanese pass later. Cheap today, expensive to retrofit.
**Requires — in place:**
- M3 proven (the schema should be derived from real content, not imagined).
- `node` on PATH for the compiler — already working, documented in
`../CLAUDE.md`.
- `BankedCall = true` re-enabled, carefully. See §7.
**Produces:** `tools/compile_dialogue.js`, `data/dialogue/*.yaml`, the banked
dialogue blob, and the bank layout that everything after M4 slots into.
**Exit:** Adding a scene requires editing a YAML file and rebuilding. Zero C
changes.
### M5 — Second regular and visitor logic
Add the stationmaster. Build the weighted arrival table from `DESIGN.md` §3 —
roll per open-hours tick, filtered by season, weather, time-of-day, and
days-since-last-visit.
**Requires — from you:**
- **Ōta's full arc** (~15 beats). Same authoring question as M3 — yours or
mine to draft.
- **Initial arrival weights**, or approval of a table I propose.
`DESIGN.md` §3 wants this tunable in a spreadsheet; I'd rather hand you a
starting table to react to than ask you to invent numbers cold.
- **How visible the pattern should be.** "The stationmaster always comes when
it rains" only lands if it's *nearly* deterministic. My instinct is to make
weather-driven arrivals much stronger than feels statistically tasteful,
because the player needs to notice.
**Requires — in place:** M4 engine and compiler.
**Produces:** visitor weight table, arrival roll, multi-arc scheduling.
**Exit:** Two arcs interleave over a week of play without colliding, and the
arrival pattern is legible enough that you can predict who's coming.
### M6 — Art pass
The real background bitmap on the palette-slot layout already reserved in
code (sky 811, wood/warm 47), plus 12 portraits (4 characters × 3
expressions). Retire the placeholder `HMMV` rectangles.
**Requires — from you:** *(this is the milestone with real lead time — start
it early, see §5)*
- **Who makes the art.** You, a commission, or an AI-assisted pipeline like
the music one. This answer determines whether M6 is a week or a quarter.
- **One background bitmap**, 256×212, 16 colors.
- **12 portraits**, 48×48, three expressions each (neutral / happy /
troubled) for the four regulars.
- **Critically: the palette spec goes to the artist *before* they draw.** Sky
tones must live in slots 811 and wood/warm tones in 47, because that
layout is what makes M7's seasons free. Art drawn in open color and
quantized afterwards will land in the wrong slots and silently destroy the
seasonal system. I can generate the exact palette table and a reference
swatch image to hand over.
**Requires — in place:**
- A PNG → SC5 conversion path. `projects/mazegame` already has working
`convert_screens.py` / `convert_tiles.py` precedent to adapt, plus MSXtk.
**Produces:** converted asset banks, page-1 warehouse layout, blit routines.
**Exit:** No procedural placeholder fills remain in the shop scene.
### M7 — Seasons, weather, palettes
Scope-ladder stage 4. Palette tables per season × time-of-day, optional lerp
across the in-game day, weather affecting the arrival table.
Deliberately placed *after* the art pass and *after* two working arcs. See §7.
**Requires — from you:**
- **How many palette sets.** 4 seasons × 3 times of day = 12 tables at 32
bytes each (384 bytes — trivial). But that's 12 moods to *art-direct*, which
is the real cost. Fewer, done well, beats twelve done mechanically.
- **Mood direction** for each: I can propose the RGB tables, but "rainy
autumn dusk" needs your eye to confirm it feels right, not mine.
**Requires — in place:** **M6 must be done.** This milestone is a no-op
without a background authored on the palette-slot layout — that dependency is
the entire reason M7 sits after the art pass instead of before it.
**Produces:** palette tables, time-of-day lerp, weather → arrival hookup.
**Exit:** A spring morning and a rainy autumn dusk are visibly different moods
on identical bitmap data.
### M8 — Remaining cast
The manga artist and the widow, full arcs. This is the largest pure-writing
block in the project — roughly 30 scenes.
**Requires — from you:**
- **Fujimoto's and Nakajima's arcs** — ~30 beats total, the single largest
writing block in the project.
- **A ruling on Nakajima's reveal.** Her second coffee is the best hook in the
cast precisely because the player solves it unaided. I need to know how far
you're willing to go without confirming it — my instinct is *very* far, and
that it should never be stated outright by anyone but her.
**Requires — in place:** M4 engine, M6 portraits.
**Exit:** All four arcs complete and reachable in one playthrough.
### M9 — Music and upgrades
68 cozy loops via the existing `msx-music-generator` pipeline. The
record-player upgrade turns the jukebox into both a feature and a home for
every generated track. Money finally gates something.
**Requires — from you:**
- **Which sound chip.** This needs settling, because the docs and your actual
toolchain disagree: `DESIGN.md` §7 and `CLAUDE.md` describe a PSG / MML →
NDP pipeline, but the working pipeline you built for `mazegame` is
`msx-music-generator`**lVGM + ayFX**, using MSX-Music (YM2413) on an
MSX2+. This project targets plain MSX2, where FM is *not* standard — it
needs an FM-PAC. Options: PSG-only (universal, thinner), FM with PSG
fallback (best sound, more work), or retarget to MSX2+. I'd take **PSG-only
through the lVGM pipeline you already have**, and treat FM as a bonus path.
Either way `DESIGN.md` §7 should be updated to match reality.
- **Briefs for 68 tracks:** mood, rough tempo, loop length. Morning,
afternoon, evening, rain, plus a theme or two for story beats.
- **Upgrade list and prices** — the point at which money finally means
something.
**Requires — in place:** money economy from M2 promoted to actually gating.
**Exit:** Music changes with time-of-day and weather; the player can choose a
record.
### M10 — Ending, polish, hardware
One quiet ending (see §6). Real-hardware verification, 50/60Hz check, timing
pass on the brew minigame.
**Requires — from you:**
- **The ending text**, and what triggers it — my recommendation is a day count
reached *after* all four arcs resolve, so it can never cut a story short.
- **Real hardware, or the machine profiles you care about.** I can only verify
against openMSX here; C-BIOS has already shown behavioural differences from
real BIOS during M1, so emulator-passing is not hardware-passing.
- **50Hz or 60Hz as the primary target** (PAL vs NTSC timing for the brew
minigame's feel).
---
## 3. The cast
`DESIGN.md` §3 suggests six to eight regulars and offers four examples. **Take
the four examples as the entire cast.** Reasoning in §6.
Each has a **want**, a **secret**, and a **change**. The want is stated early.
The secret is never announced — it's inferred from behaviour, then eventually
confirmed in one quiet line. The change is small and late.
### Hoshino Aki — the exam student
- **Usual:** cream soda float. A child's order they're faintly embarrassed by.
- **Rhythm:** weekday evenings, then scarcer as exams approach.
- **Want:** to pass the Tokyo entrance exams.
- **Secret:** the course is their parent's choice. They want to study
something else and haven't said so to anyone.
- **Change:** orders coffee instead — once, without comment. The player will
notice before they understand it.
- **Why first:** the arc is legible, the usual is visually distinct from every
other order, and the change is expressible entirely through the serve
mechanic.
### Ōta-san — the retired stationmaster
- **Usual:** black coffee, no sugar. Arrives at the same minute daily.
- **Rhythm:** early hours; rain makes him certain to appear.
- **Want:** to have somewhere to be at a fixed time.
- **Secret:** the line he worked was cut back before he retired. The precision
he still keeps is for a timetable that no longer exists.
- **Change:** stops apologising for lingering.
### Fujimoto — the manga artist
- **Usual:** strongest coffee available, endless refills, toast set when
reminded to eat.
- **Rhythm:** very late; a monthly deadline cycle drives their frequency and
their panic.
- **Want:** to finish the chapter.
- **Secret:** the series is ending, and they come here to be somewhere that
isn't the desk.
- **Change:** the shop appears in the manga. They show you the page.
### Nakajima-san — the widow
- **Usual:** two coffees. Always two.
- **Rhythm:** slow, seasonal, tied to specific weather and dates.
- **Want:** to keep a routine that belonged to two people.
- **Secret:** the second coffee is his order, and it goes cold every time.
- **Change:** one day she orders one. No speech about it.
- **Note:** her hook is the strongest in the cast because it's **visible in
the serve mechanic before it is ever explained**. The player solves it
themselves. Protect that — do not have anyone explain her early.
---
## 4. Story architecture
### Arc shape
Twelve to eighteen beats per character. A beat is three lines of 26
characters — a *moment*, not a scene.
| Beats | Function |
|---|---|
| 13 | Establish the routine. Player learns the usual. |
| 48 | A crack. Mentioned in passing, never explained. |
| 914 | It develops. Serving choices nudge; they never gate. |
| 15+ | Resolution — quiet, undramatic, small. |
Cozy resolves **gently**. No reveals, no tragedy delivered as a twist. Ōta
doesn't confess a catastrophe; he admits the house is too quiet now. Restraint
is the genre, and it's also cheaper to write well than melodrama is.
### Authoring order
Write **one arc completely** before starting the next. Writing everyone's
first three beats produces four strangers and no one you know.
### Trigger vocabulary
The scene format is `(conditions) → (portrait, expression, text, effects)`.
The condition language is the real design work — keep it minimal:
```
day >= N season == S
arc_stage == N weather == W
affinity >= N phase == P
served == ITEM absent >= N days
```
Eight condition types cover every behaviour described in `DESIGN.md`.
**Resist adding a ninth.** Every addition multiplies the authoring surface and
the testing burden, and the temptation will be strongest exactly when the
writing is hardest.
### Effects
Scenes may raise affinity, advance `arc_stage`, set a flag, or unlock an item.
Nothing else. No arbitrary state mutation — that path ends in a scripting
language nobody asked for.
### Text and localisation
Current font is ASCII at 26 characters per line. `DESIGN.md` §9 flags the
Japanese retro community as a real slice of the audience.
**Recommendation:** don't build kana support now, but route every player-facing
string through an ID from the start. A Japanese pass then becomes a font and a
table swap rather than re-authoring the entire script. This costs almost
nothing today and is expensive to retrofit.
---
## 5. Budgets
### ROM — not a constraint
| Item | Size |
|---|---|
| Stage 1 code | ~17 KB |
| All dialogue text (~8,000 chars) | ~8 KB |
| Portraits (4 × 3 × 48×48 @ 4bpp) | ~14 KB |
| Background bitmap (256×212 @ 4bpp) | ~27 KB |
| Music (68 lVGM loops) | ~20 KB |
Comfortably inside 128 KB with room for a second background or seasonal
variants if they ever prove necessary. **ROM size will not be what limits this
project.**
### Writing — the actual constraint
Four characters × ~15 beats = **~60 scenes**. At three beats per sitting that
is twenty writing sessions. This is the single largest line item in the
project and it does not compress.
**Status: a complete first draft exists** in `SCRIPT.md` — all 60 beats, plus
order lines, per-character brew reactions and ambient lines, every line
checked against the 26-character box. What remains is your edit pass, which is
a different and much smaller job than writing from nothing.
### Art — the long pole
12 portraits and one background. Tractable at four characters; at eight it
roughly doubles and becomes the thing that stalls the project.
**Open question:** who draws these? The plan assumes 12 portraits exist by M6.
If that's commissioned or AI-assisted work, it needs starting well before M6,
since it's the only item here with external lead time.
---
## 6. Deliberate cuts
| `DESIGN.md` says | Plan says | Why |
|---|---|---|
| 68 regulars | **4** | 8 × 15 scenes and 24 portraits is where this project dies. Four in a small provincial kissaten is also *more* intimate — the cut serves the atmosphere pillar rather than fighting it. |
| Money economy | Minimal until M9 | Gates nothing before the record player. |
| "Endings" (plural) | **One** quiet ending | Per-character arc completions already provide the sense of closure. Multiple endings multiply testing for a game with no fail state to contrast against. |
| Morning menu planning | Deferred, possibly cut | Adds a decision phase before the loop that carries the game. Revisit only if open hours feel thin. |
| Branching dialogue choices | Defer to M4 | M3 will reveal whether they're needed at all. My expectation: rarely. |
"Small, finishable scope. When in doubt, cut." — `CLAUDE.md`, design pillars.
---
## 7. Risks and known hazards
**Seasons are procrastination.** M7 is the most enjoyable thing on this list —
palette work produces beautiful results in minutes with no writing involved.
It will call loudly every time the script gets difficult. It also adds nothing
to whether the game is *good*. Keep it as the reward after two arcs work.
**Engine-before-content.** The reason M3 is hardcoded. Dialogue systems get
over-built when designed before any dialogue exists; you end up supporting
features nothing uses and discovering the one thing you need is awkward.
**Cast creep.** Four will feel thin around M5, when two arcs exist and the
shop seems empty. It won't feel thin at M8. Do not add a fifth regular before
all four are complete.
**`BankedCall = true` is a known hazard.** Enabling it with nothing actually
banked corrupted RAM globals — the state machine ran wild. It's off, and M4 is
the deliberate point to turn it back on, with the banked data that justifies
it. See the platform gotchas in `../CLAUDE.md`.
**Keyboard reads need interrupt protection.** Documented in `../CLAUDE.md`;
applies to every new input added.
---
## 8. Decision queue
Everything the milestones above need from you, in the order it becomes
blocking. Items marked **lead time** should be started well before the
milestone that consumes them.
| # | Needed for | Decision | My recommendation |
|---|---|---|---|
| 1 | M2 | ~~Save medium~~**save disk (.dsk), asset supplied** | ⚠ decided, but **not working yet** — see the disk section in `../CLAUDE.md`. Sector I/O reports success without transferring. **The RTC CMOS fallback I previously suggested is not viable**: block 3 is 13 nibbles, and MSXgl's `RTC_SaveData()` stores **6 bytes**, against a ~40-byte `SaveState`. Real fallbacks are cartridge SRAM, the FM-PAC SRAM, or shrinking the save to a 6-byte fingerprint |
| 2 | M2 | ~~Day length~~**5 min / 5 customers** | ✅ done. One constant, `CUSTOMERS_PER_DAY` in `kissaten.c` |
| 3 | M2 | ~~Clock model~~**event-driven** | ✅ done. Customers are the clock |
| 4 | M3 | ~~Who writes the dialogue~~**drafted by me, you edit** | ✅ resolved |
| 5 | M3 | ~~Aki's six beats~~ | ✅ drafted — all four arcs are in `SCRIPT.md`, awaiting your edit |
| 6 | M3 | Scratch portrait for Aki | Crude is fine, but *something* — the test needs a face |
| 7 | M3 | Item list at slice stage | Coffee + cream soda only |
| 8 | **M6 — lead time** | **Who makes the art** | Decide now, not at M6; it's the only external dependency |
| 9 | M4 | Scene schema sign-off | Ten-minute review, saves a rewrite |
| 10 | M4 | String IDs for future JP text | Yes — nearly free now, expensive later |
| 11 | M5 | Arrival weights | React to a table I propose |
| 12 | M6 | Palette spec to artist **before** drawing | Non-negotiable if M7 is to stay cheap |
| 13 | M7 | Number of palette sets | Fewer, art-directed well |
| 14 | M8 | How overt Nakajima's reveal gets | Never stated by anyone but her |
| 15 | M9 | Sound chip: PSG / FM / retarget | PSG-only via your existing lVGM pipeline |
| 16 | M10 | Hardware access + 50/60Hz target | — |
Items 13 are small and I can proceed on my recommendations if you'd rather
not think about them. Items 4 and 8 are the two that genuinely shape the
project, and both want answering now.
## 9. Immediate next actions
1.**M2 day spine** — day counter, three phases, journal line. Done and
playable. **Persistence still blocked**; see the disk section in
`../CLAUDE.md` for everything established so far.
2.**Aki's beats as prose** — done, along with the other three arcs, in
`SCRIPT.md`. Awaiting your edit pass.
3.**Unblock saving.** Either keep digging at the disk path, or switch
medium. Note the RTC CMOS fallback is off the table (§8 item 1).
4.**Start the portrait question** (§5) — still the only item with external
lead time, and now the longest pole by some distance.
3 and 4 are independent; 4 can start today and should.
+492
View File
@@ -0,0 +1,492 @@
# Kissaten Yūgure — Script
First draft of all four character arcs, plus order lines, brew reactions and
ambient lines. Written as prose-first per `PLAN.md` §9 — no data format yet.
**This is a draft to edit, not to approve.** The characters are yours; if
anyone's voice is wrong, it's wrong now and cheap to fix.
---
## How to read this
Every beat is one dialogue box: **3 lines × 26 characters**, ASCII, as laid
out in `DESIGN.md` §4. Every line here has been checked against that limit.
```
**B4 · the crack** — `day>=7` — troubled
Mock exam results came.
Law faculty. Tokyo.
Father framed the sheet.
```
- **B4** — beat number. Beats fire in order; a beat's trigger is *also*
gated on the previous beat having played (`arc_stage`).
- **Trigger** — conditions from the vocabulary in `PLAN.md` §4.
- **Expression**`neutral` / `happy` / `troubled`. Three per character, per
`DESIGN.md` §5.
Triggers are deliberately loose. Tighten them once pacing is playable —
day numbers here assume roughly one visit per character per 2 days.
---
## 1. Hoshino Aki — the exam student
> Cream soda. Weekday evenings, scarcer as exams approach.
> **Want:** pass the Tokyo entrance exams.
> **Secret:** the course is her father's choice. She wants astronomy, at a
> small college in Sendai with an observatory on the roof.
> **Change:** orders coffee instead of the soda.
The dusk sky through the shop window is her arc's spine — she is the reason
that window is there. **Beats 16 are the M3 vertical slice.**
**B1** — `day>=2, phase=evening` — neutral
Cream soda, please.
The big one, if that's
all right.
**B2** — `day>=3` — neutral
Exams in the spring.
They say third year goes
fast. It hasn't.
**B3** — `day>=5, served=CREAM_SODA` — happy
You remembered.
Nobody at home remembers
what I like.
**B4 · the crack** — `day>=7` — troubled
Mock exam results came.
Law faculty. Tokyo.
Father framed the sheet.
**B5** — `day>=9, weather=rain` — neutral
Can't see the sky today.
...Sorry. That was a
strange thing to say.
**B6 · slice ends** — `day>=11, served=CREAM_SODA` — neutral
Master, do you ever look
out that window and think
about anything else?
**B7** — `day>=13` — troubled
Father's friend teaches
at the Tokyo faculty.
It's arranged, basically.
**B8** — `day>=15, absent>=3` — troubled
Sorry I haven't come.
Cram school added hours.
I missed this place.
**B9** — `day>=17, affinity>=60` — neutral
There's a small college
in Sendai. They have an
observatory on the roof.
**B10** — `day>=19` — happy
I wrote for a prospectus.
It came in a brown
envelope. I hid it.
**B11** — `day>=21, weather=clear, phase=evening` — happy
Look - that's Vega.
You can see it even from
town, if you know where.
**B12** — `day>=23` — troubled
Applications close on
the twentieth.
I haven't told them.
**B13 · the change** — `day>=25, served=COFFEE` — neutral
Not the soda today.
Coffee. Black, like you
make for Ota-san.
**B14** — `day>=27` — troubled
I told them.
Mother cried. Father
hasn't spoken since.
**B15 · resolution** — `day>=30` — happy
Sendai. I posted it.
Father drove me to the
post office. Said nothing.
---
## 2. Ōta-san — the retired stationmaster
> Black coffee, no sugar. Early mornings. Rain makes him certain.
> **Want:** somewhere to be at a fixed time.
> **Secret:** the ten-fifteen was cut in his last spring. His precision keeps
> a timetable that no longer exists.
> **Change:** stops apologising for lingering; orders a second cup.
**B1** — `day>=1, phase=morning` — neutral
Coffee. Black.
Seven forty. You open
at seven forty.
**B2** — `day>=3, phase=morning` — neutral
Your father opened at
seven forty as well.
I never asked him why.
**B3** — `day>=5, weather=rain` — neutral
Rain. I always came in
the rain. The platform
had no roof at the end.
**B4** — `day>=7, served=COFFEE` — happy
Thirty-one years I
poured tea on that
platform. Never coffee.
**B5 · the crack** — `day>=9` — troubled
They cut the ten-fifteen
in my last spring.
Nobody came to say so.
**B6** — `day>=11` — neutral
I still wake at five.
The body keeps a
timetable of its own.
**B7** — `day>=13, absent>=2` — troubled
Forgive me. I'm keeping
your counter. I'll go.
...No. Not yet.
**B8** — `day>=15, affinity>=50` — neutral
The house is not small.
That is the trouble.
It was sized for four.
**B9** — `day>=17` — neutral
My daughter telephones
on Sundays. Eleven a.m.
She is very punctual.
**B10** — `day>=19, weather=rain` — happy
You knew I'd come.
The pot was already on.
That is a fine thing.
**B11** — `day>=21` — neutral
The station is a
convenience store now.
I have not gone in.
**B12** — `day>=23` — troubled
I went in. For batteries.
The ticket window is
where the freezers are.
**B13** — `day>=25, affinity>=80` — neutral
You keep good time,
Master. That is not a
small compliment from me.
**B14 · the change** — `day>=27` — happy
I'll have a second cup.
I am not going anywhere
in particular today.
**B15 · resolution** — `day>=30` — happy
Seven forty.
Tomorrow also, I think.
That is all I wanted.
---
## 3. Fujimoto — the manga artist
> Strongest coffee, endless refills, toast set when reminded to eat.
> Very late. Frequency and panic follow a monthly deadline cycle.
> **Want:** finish the chapter.
> **Secret:** the series is being cancelled. Comes here to be anywhere that
> isn't the desk.
> **Change:** the shop appears in the final chapter.
Fujimoto carries the comedy. A cozy game with four sad people is not cozy —
it's a wake. Let them be funny about their own misery.
**B1** — `day>=2, phase=evening` — neutral
Strongest you have.
No, stronger. I have
eleven pages by Friday.
**B2** — `day>=4` — troubled
Do you know how long
eleven pages is?
Neither do I anymore.
**B3** — `day>=6, served=COFFEE` — neutral
Refill. And again after.
I'll pay for the pot.
Cheaper by the hour.
**B4** — `day>=8` — troubled
Editor called me
'reliable' today. That's
what they say before.
**B5** — `day>=10, absent>=4` — troubled
Four days at the desk.
I have drawn one hand.
It's a bad hand.
**B6 · the crack** — `day>=12` — troubled
I don't come here to
work, Master.
I come here to not.
**B7** — `day>=14, served=TOAST` — happy
When did I last eat?
Don't answer that.
...Thank you for this.
**B8** — `day>=16` — neutral
Thirty-two volumes.
Nine years. My whole
twenties, in a drawer.
**B9 · the secret** — `day>=18, affinity>=50` — troubled
They're ending it.
Two more chapters.
I asked for three.
**B10** — `day>=20` — troubled
Nine years and I get
two chapters to say
goodbye properly.
**B11** — `day>=22` — neutral
I've been drawing this
counter. Not for work.
Just drawing it.
**B12** — `day>=24, weather=rain` — neutral
Rain's good for pages.
Nobody expects you
anywhere in the rain.
**B13 · the change** — `day>=26, affinity>=70` — happy
The last chapter is
set in a coffee shop.
I hope that's all right.
**B14** — `day>=28` — happy
Here. Page forty.
That's your counter.
That's your lamp.
**B15 · resolution** — `day>=31` — happy
It's done. Nine years.
I'm starting something
new. Set here, I think.
---
## 4. Nakajima-san — the widow
> Two coffees. One with milk, one black. Slow, seasonal, weather-tied.
> **Want:** keep a routine that belonged to two people.
> **Secret:** the second coffee is his. It goes cold every time.
> **Change:** one day she orders one.
**Handle with care.** Her hook is the strongest in the game because the
player solves it unaided — the order is visible in the serve mechanic long
before anything is said. Per `PLAN.md` §8 item 14: **no one but Nakajima-san
ever explains it**, and she does so obliquely, at B4, and never apologises
for it. Do not let another character mention her situation.
Her arc runs on a slower day scale than the others by design — she should
feel like someone you see less often.
**B1** — `day>=4` — neutral
Two coffees, please.
One with milk.
The other black.
**B2** — `day>=8` — neutral
The same, please.
You remember which is
which. That's good.
**B3** — `day>=12, served=TWO_COFFEE` — neutral
No, don't clear it yet.
Leave it a while.
I'm not finished.
**B4 · the crack** — `day>=16, season=autumn` — neutral
He liked the autumn.
Said the town looked
better in brown.
**B5** — `day>=20` — neutral
Forty-one years of
two coffees.
It's a hard habit.
**B6** — `day>=24, weather=rain` — troubled
He'd have hated today.
He walked everywhere.
Never once took a bus.
**B7** — `day>=28, affinity>=40` — neutral
Your father served us
at that end table.
We were young then.
**B8** — `day>=32` — neutral
I know it goes cold.
That isn't the point
of it, Master.
**B9** — `day>=36, season=winter` — troubled
Three years this month.
People stop asking after
the second one.
**B10** — `day>=40` — neutral
My son says it's time
I stopped. He means
well. He means well.
**B11** — `day>=44, season=spring` — neutral
The cherry by the
station is out.
He'd have said it's early.
**B12** — `day>=48, affinity>=70` — neutral
I don't cry about it.
I just like ordering
for two. It's an hour.
**B13** — `day>=52` — neutral
You never asked me why.
That's why I come here
and not the new place.
**B14 · the change** — `day>=56` — neutral
One coffee today.
...With milk.
Just the one.
**B15 · resolution** — `day>=60, affinity>=90` — happy
One, please.
I'll take the window
seat. He never liked it.
---
## 5. Order lines
Spoken on arrival, before the brew. Rotate at random within a character;
they're texture, not story.
**Aki**
Cream soda, please.
The usual, Master.
Soda. I've earned it.
**Ōta-san**
Coffee. Black.
The usual, if you please.
Coffee. No sugar. Ever.
**Fujimoto**
Coffee. Keep it coming.
Something that will hurt.
Strongest. And toast.
**Nakajima-san**
Two coffees, please.
The same as always.
Two. Milk in one.
---
## 6. Brew reactions
Replaces the generic quality lines currently hardcoded in `kissaten.c`.
Quality bands as implemented: 3 = perfect, 2 = good, 1 = fair, 0 = off
(thin or over-strong depending on which side of centre you locked).
| | Aki | Ōta-san | Fujimoto | Nakajima-san |
|---|---|---|---|---|
| **3** | The ice is just right. | That is correct coffee. | Oh, that's cruel. Good. | He'd have liked that one. |
| **2** | Mm. That's a good one. | Good. Very good. | That'll do damage. | Very good, Master. |
| **1** | Thank you, Master. | Thank you. | Fine. It's wet. | Thank you, dear. |
| **0 thin** | It's a bit flat today. | A little pale today. | Is this tea? | A little weak today. |
| **0 strong** | Ooh. That's a lot. | Strong. I'll manage. | Perfect. Awful. Perfect. | Oh my. That's bracing. |
---
## 7. Ambient lines
Shown while the shop is empty. The four currently in `kissaten.c` are
placeholders; these replace them. Weather- and season-gated where marked.
**Any time**
The radio hums softly.
The kettle ticks as it
cools.
Steam on the window glass.
A bicycle bell, outside.
The lamp buzzes, once.
**Rain** — `weather=rain`
Rain taps at the window.
Someone runs past under
a newspaper.
The gutter is singing.
**Clear evening** — `weather=clear, phase=evening`
Dusk settles over the
street.
The sky goes orange, then
nothing.
**Autumn** — `season=autumn`
A leaf is stuck to the
door.
**Winter** — `season=winter`
The window fogs faster
than you can wipe it.
---
## 8. Notes and open questions
**Aki's soda doesn't fit the brew minigame.** The siphon minigame is
coffee-specific, but her usual is a cream soda. My recommendation: **soda
skips the minigame entirely** — it's poured, not brewed. That's not a
workaround, it's an improvement: her visits get a different, lighter rhythm
than the three coffee drinkers, which suits a teenager dropping in after cram
school. Her B13 switch to coffee then means she enters the minigame for the
first time, which is a lovely mechanical echo of the story beat.
**Nakajima-san's two coffees imply a two-brew serve.** Simplest reading: one
minigame, both cups. Making the player brew twice would be tedious and would
also make the second cup feel like a chore rather than a small sadness.
**Cross-references are deliberate.** Aki's B13 names Ōta-san; Ōta's B2 and
Nakajima's B7 both reference your father running the shop before you. These
cost nothing and make the cast feel like one place rather than four
unrelated visitors. Add more of these freely — but never let anyone discuss
Nakajima-san's second cup.
**Nobody dies during the game, nobody is cured.** All four arcs resolve by
someone deciding something small. That is the genre working correctly.
**Beat count is 60.** At three beats per sitting that's the twenty writing
sessions budgeted in `PLAN.md` §5 — already spent, if this draft survives
editing.