Files
mazegame/projects/kissaten_yugure/docs/PLAN.md
T
jurjen.ladeniusandClaude Opus 5 70b42f6da1 Plan: add M10 save slots (multi-file), renumber polish to M11
tool/disk_save already indexes every call by entry, so multiple save files
cost almost nothing on the storage side — KISSAT00.SAV, KISSAT01.SAV, and
DiskSave_Check/Delete/GetFreeEntries already exist per entry. The work is
the boot-time slot screen, which is why it sits late: it is easier to
design once there is real save content to display.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 22:21:01 +02:00

25 KiB
Raw Blame History

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: complete. Day counter, three phases, journal line, SaveState and disk persistence all working. Verified by playing a day, cold-booting, and resuming at day 2 with the served count intact.

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 — the slot screen is already a boot-time front-end, so "how long should a day be?" has a natural home there, asked once when a new shop is started. 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-generatorlVGM + 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 — Save slots (multi-file)

Several shops on one disk. tool/disk_save is already built for this: every call takes an entry index, so slots become KISSAT00.SAV, KISSAT01.SAV and so on with no change to the save format. DiskSave_Check(entry) reports each slot's state, DiskSave_GetFreeEntries() counts the free ones, and DiskSave_Delete(entry) removes one. The storage side is nearly free.

The actual work is front-end: a slot screen at boot showing what's in each one, and a confirm step before overwriting or deleting. That is also why this milestone sits late — it touches the boot flow, and it is much easier to design once there is real save content to display.

Worth framing in-fiction rather than as a file manager. A slot is not "Save 1", it is a shop with days behind it — "Day 34 · 210 cups" tells the player which one is theirs better than a filename does.

Requires — from you:

  • How many slots. Three is conventional and the disk has room for far more; the constraint is screen space, not storage.
  • Whether slots are named. A proprietor's name per shop is charming, but it means building text entry on a machine with no line editor. My recommendation: skip it, and let day count plus cups served identify a slot.
  • What the deletion guard is. No fail states applies to the save screen too — an accidental delete is the one genuinely unrecoverable action in a game that otherwise has none. I would make it a two-step confirm.

Requires — in place: M2's save layer (done). Nothing else technically — this could be built any time, and is late only because the design benefits from real content.

Produces: slot selection screen, per-slot summary, delete with confirm, SAVE_ENTRY becoming a runtime value rather than the #define it is now.

Exit: Three shops can be run in parallel from one disk, each resuming to its own day and cast state, and no single keypress can destroy one.

M11 — 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 mediumsave disk (.dsk) working, via MSXgl's tool/disk_save module. Saves KISSAT00.SAV to drive A. Four non-obvious requirements — see the disk section in ../CLAUDE.md
2 M2 Day length5 min / 5 customers done. One constant, CUSTOMERS_PER_DAY in kissaten.c
3 M2 Clock modelevent-driven done. Customers are the clock
4 M3 Who writes the dialoguedrafted 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 Number of save slots, and whether they're named 3 slots, unnamed — day count and cups served identify them without needing text entry
17 M11 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. M3 vertical slice — Aki's first six beats, hardcoded, with a scratch portrait. The next real milestone, and the one that decides whether the game works (§2, M3).
  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.