Keep the pole in one hand, and write the session up

Oliver spotted it before testing: a whole-frame mirror swaps the DRAGGED POLE
into the other hand as well as the legs. True for the one wound stage that still
has an arm holding something, so that stage gets a leg-band mirror about the hip
centre instead — legs swap, pole and stump stay put. The other three stages have
no arms and no props, so a full mirror is right for them.

The honest cost: a leg mirror leaves both feet in the same two places, so that
one frame reads as a leg swap rather than a stride. Written up with the fix that
worked for the shamblers (a passing pose, feet together) and the measurement that
tells them apart.

HANDOFF gets the session: what changed, the two lessons that cost the most (the
prompt sets the art resolution; the reference sheet is what the generator
copies), the rule that anything which must stay identical between two frames
belongs in code, and the four known limitations ranked for whoever picks it up.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-07-31 23:10:52 +02:00
1 parent 2f8aca69d9
commit f71d9293fc
4 files changed
+51 -2

No files matched your search

+49
View File
@@ -397,6 +397,55 @@ Known generator quirks, all still true:
- **Colour-match any regenerated frame** of an existing pair before shipping: fit a per-channel
linear map onto the original's mean and sd, then verify with a mean-difference number.
## Session log: the art-resolution pass (2026-07-31)
**What changed.** The whole character roster was redrawn at real pixel-art resolution, plus a batch
of gameplay fixes. Everything is on `main` and deployed; the start screen shows a BUILD timestamp
so a phone can be checked against `git log -1 --format=%cd`.
Gameplay this session: the horde machine-gun buffed until a grown wave is survivable (rate scales
with hordeGrow, fat pellets, 2 hp each) and `hordeRate` raised to leave a standing crowd behind;
the steward ('d') added as an ordinary body between shambler and brute; a pending horde can no
longer fire into a boss fight; bodies stopped blinking on the way in (negative-z modulo); the ball
machine rolls, dents, and dies as machinery with smoke; the player's death is five drawn frames
with the crowd converging and dispersing; wounded bodies walk; side-on zombies mirror when they
walk right; the racket zombie's cycle steps off ground covered.
**The lesson that cost the most.** The prompt sets the art resolution, and I set it wrong for
eleven sheets by asking for "big chunky pixel blocks, flat colour, no shading". See pipeline note 9.
**The lesson that cost the second most.** THE REFERENCE SHEET IS WHAT THE GENERATOR COPIES. Building
it out of the sprites you are trying to change reproduces exactly what you wanted gone — a
front-facing player stayed front-facing and a side-on runner stayed side-on through three retries
each. `_regen_batches.json` supports `ref_only` for this: the frames it LOOKS at, separate from the
frames it replaces. Draw the back view from the one true back-view frame; draw a front-facing
sprint from a front-facing zombie.
**Anything that must stay pixel-identical between two frames: do it in code, not in a prompt.** The
brute's wound moved between his two feet across three separate regeneration attempts. B frames are
mirrors of their A frame now.
**Known limitations, in priority order for the next session:**
- `z_gwb` (brute, one arm gone, dragging the pole) is a LEG-BAND mirror of `z_gw`, because a whole
frame mirror swaps the pole into the other hand. A leg mirror keeps both feet in the same two
positions, so it reads as a leg swap rather than a stride. The fix that worked for the shamblers:
generate the second frame as a PASSING pose (feet together under the body, one knee lifted) with
the prop explicitly in the same hand — a walk needs the foot GAP to open and close, which is the
measurement to check (`z_aw` 75px -> `z_awb` 65px is a real stride; equal gaps are not).
- Brute damage stage 3 was drawn slimmer than the others once; watch that the four stages keep one
body size (they are drawn from `z_g1` in two sheets now).
- "Player looks transparent while running" was reported and then reported gone. Never reproduced:
the run frames have zero semi-transparent pixels and every globalAlpha in render.js is
save/restore'd. If it returns, establish first whether the court shows THROUGH him (sprite) or he
flickers (renderer).
- The chapter bosses, the judge, the ball machine and the weapon icons were deliberately NOT
redrawn — Oliver named them as already right.
**A sprite's drawn size comes from its TOTAL height**, so anything held above the head eats into the
body. The serve frames were 29% racket by height and the man came out a fifth too small; they are
scaled so the BODY matches the standing frame (98% of sprite height) and the racket overhangs. Check
this on any new pose with a raised prop.
## Gotchas learned the hard way
- **Stale ES modules are the #1 time sink.** python http.server sends no cache headers, so an edited
module often loads STALE. `preview_stop`/`preview_start` only helps if the port actually changes,
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

+1 -1
View File
@@ -97,6 +97,6 @@
<p id="build"></p>
</div>
</div>
<script type="module" src="main.js?v=75"></script>
<script type="module" src="main.js?v=76"></script>
</body>
</html>
+1 -1
View File
@@ -155,7 +155,7 @@ export function proj(x, y, z) {
// ---------------------------------------------------------------- sprites ----
// assets/<name>.png; game falls back to code-drawn figures until sprites load.
const SPRV = 68; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
const SPRV = 69; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
const SPR = {};
for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','p_run1','p_run2','p_run3','p_run4','p_swing1','p_swing2','p_die1','p_die2','p_die3','p_die4','p_die5',
'o_idle1','o_idle2','o_bounce','o_bounce2','o_toss','o_smash','o_run1','o_run2','o_swing1','o_swing2',