Files
mazegame/projects/kissaten_yugure/docs/PLAN.md
T
jurjen.ladeniusandClaude Opus 5 45749775fa 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>
2026-07-27 21:58:22 +02:00

519 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.