Commit Graph
9 Commits
Author SHA1 Message Date
jurjen.ladeniusandClaude Opus 5 aa8fa3ddf9 Art: emit the palette as .gpl/.ase/.aco as well as .act
The .act files only helped Photoshop. Affinity imports .ase and .aco;
Inkscape, GIMP, Krita and Aseprite want .gpl. tools/make_palettes.py now
generates all four plus swatch PNGs, for both the full 16 and the
11-colour portrait subset, all derived from the same PALETTE table shared
with kissaten.c so nothing can drift.

Colour names ride along in .gpl/.ase/.aco, so the swatches show up labelled
("skin", "lamp glow", "dusk violet") rather than as anonymous chips.

.ase output verified by reading it back and checking all 11 colours
round-trip exactly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 21:34:14 +02:00
jurjen.ladeniusandClaude Opus 5 db7de024de Art: SVG -> 48x48 portrait converter, and it works
Magnific's SVG export is flat-shaded vector (~550 solid-fill paths, 6
gradients), which converts to pixel art cleanly. tools/svg2portrait.py
rasterises at 16x the target via qlmanage, then takes the most common
colour per 16x16 block — a true pixelate with no blending — and maps to
the 11-colour portrait palette.

Measured on Aki: 19 colours after pixelate, 10 after palette, visually
near-identical. So the portrait palette is sufficient for this art.

Contrast with the bitmap route this replaces: a 48x48 PNG resized in
Photoshop had 1330 unique colours in 2304 pixels, because bicubic
resampling turns flat regions into gradients. Quantising that speckled
badly across the blazer and background.

Also adds tools/pixtool.py — dependency-free PNG decode/encode (no Pillow
on this machine) plus the palette table shared with kissaten.c.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 20:46:12 +02:00
jurjenwerk 1c0d2d9a88 Add AKI images 2026-07-28 11:41:10 +02:00
jurjen.ladeniusandClaude Opus 5 60c9e13fa8 Art brief: give each asset type its own palette block
The palette constraint is not uniform across assets, so a single generic
line was not enough:

- Portraits list only the 11 non-sky colours, since a face never shows sky;
  omitting the sky slots is safer than asking a generator to avoid them.
  Adds the flat #492424 backdrop requirement (HMMM blits have no
  transparency, so whatever surrounds the head gets copied literally).
- The background block is split by region: four sky colours inside the
  window opening, eleven interior colours everywhere else, with the frame
  and mullions counted as interior wood. Also reserves the top 16 and
  bottom 64 rows the game draws over.
- Sprites take no palette at all — they are hardware sprites coloured at
  runtime, so the art only defines shape.

Notes that the available clothing colours are few enough that characters
need distinct ones or they blur together in the dialogue box.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 10:23:34 +02:00
jurjen.ladeniusandClaude Opus 5 25a098e6af Add art brief and palette references for the PixelLab pipeline
Resolves decision 8: art is generated in PixelLab from written prompts.
docs/ART.md carries the palette spec, the sky/wood slot rule, per-asset
sizes and return format, and prompts for Aki (needed for M3), the rest of
the cast, and the shop background.

art/palette.png (16x1, one pixel per entry) and art/palette_ref.png
(512x64 swatch strip) are generated from g_Palette so the generator and
the build cannot drift apart.

Flags a constraint the palette had hidden: only one literal skin entry, so
portraits use 6 -> 14 -> 4 as a hue-compatible skin ramp.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 22:34:05 +02:00
jurjen.ladeniusandClaude Opus 5 97eebbaefc Plan: park the M10 save-slot choices as deferred decisions
Records slot count, naming, presentation, delete guard and the day-length
dial as decision-queue items 16-20 marked "defer": captured so the
reasoning survives, but explicitly not decided now. They only bite at M10
and are all easier to judge against a real slot screen than in the
abstract. Adds a "defer" convention to the queue preamble.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 22:26:54 +02:00
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
jurjen.ladeniusandClaude Opus 5 cbde457da5 M2 complete: disk saving works via MSXgl's tool/disk_save module
Replaces the hand-rolled PHYDIO/DSKIO sector writer, which never worked,
with engine/src/tool/disk_save.h — added in MSXgl v1.3.0 for exactly this
("save to disk from a ROM application"). Saves are now a real FAT file,
KISSAT00.SAV, on the disk in drive A.

Four non-obvious requirements, all documented in CLAUDE.md:
- LibModules needs both "tool/disk_save" and "dos"
- ROMDelayBoot = true, or the Disk ROM's INIT never runs
- boot then takes 40-90s of emulated time (use `set throttle off`)
- DiskSave_Check() returns SAVEDATA_UNSIGNED for good files: with APPSIGN
  it wants the first 4 bytes to be g_AppSignature, but DiskSave_Save()
  writes the payload raw and never adds it

Also fixes a save-timing bug: the write now happens in AdvanceDay() after
the day increments, so the file describes the morning the player wakes to.
Saving during the evening made a reload replay that day and double-count
its cups.

Verified: play a full day, cold boot, resume at day 2 with served intact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 22:17:49 +02:00
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