Nothing arrives unannounced: the horde gets its breather, the boss gets a name
THEY KEEP COMING is a 2.4s 'over' beat again (warnHorde in beats.js) instead of a flash raised on the same frame the wave lands, and the chapter boss walks on behind an overlay — his name in red over ENTERED THE COURT — held for 3s by the new self-dismissing modal clock (m.hold) rather than announced on a routine-set card. startHorde returns a bool: if the court has been taken when the warning expires the pendingHorde latch is re-armed rather than the set losing the horde it paid for. The warning ticks on its own clock, not on the 'over' beat, so a beat that moves the phase underneath it can't strand it (the mgT lock, again). Three tests, 15 total. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1f636530b9
commit
5ea84f8511
8 files changed
+132
-16
No files matched your search
+34
-1
@@ -10,7 +10,8 @@ detail of any individual change, read the git log.
|
||||
the state-machine contracts that have historically produced the show-stoppers. The Dockerfile runs
|
||||
it as a build stage, so a red suite cannot deploy — but finding out from Coolify is the slow way.
|
||||
|
||||
Last updated 2026-08-11 (beats.js extraction, this file renamed, tests gate the build). **Start with "How to work on this", "OPEN — leftovers" and "LATER —
|
||||
Last updated 2026-08-11 (the horde's breather restored, the boss walk-on overlay; beats.js
|
||||
extraction, this file renamed, tests gate the build). **Start with "How to work on this", "OPEN — leftovers" and "LATER —
|
||||
shipping it"** (all three just above the CLOSED sections) — the first tells you how Oliver's feedback
|
||||
should be handled, the second is everything known to be outstanding in the game, the third is the
|
||||
demo/store/campaign plan, which is decided but entirely unbuilt. All four playtest rounds are closed
|
||||
@@ -101,6 +102,11 @@ zombie (now an occasional opponent, `TUNE.racketEvery`, not the every-game fixtu
|
||||
left, all on `easeOutBack`; every x is `Math.round`ed, because a fractional x on a nearest-neighbour
|
||||
scaled image re-snaps its pixel columns (the boiling that once read as HUD flicker). A modal with no
|
||||
`in` field draws fully landed, so older/test call sites still work.
|
||||
**`m.hold` is an optional self-dismiss clock** (seconds, ticked only once `m.in` has landed): the
|
||||
modal announces, holds the frozen court, and lets go by itself. The chapter-boss walk-on is the
|
||||
case it exists for — an announcement whose job is to PREPARE the player, where demanding a tap to
|
||||
start a fight he did not ask for would be the control steal the popup policy exists to prevent.
|
||||
A tap still skips it. Every other modal has no `hold` and waits for the player, as before.
|
||||
While `m.in < 1`, `dismissModal` **returns true without dismissing** — it swallows the gesture but
|
||||
won't let a panic tap that was already mid-air skip a popup nobody has read. Returning false there
|
||||
would drop that tap through into a serve instead.
|
||||
@@ -380,6 +386,33 @@ zombie (now an occasional opponent, `TUNE.racketEvery`, not the every-game fixtu
|
||||
`RETURNED`, `DOUBLE KILL`) is a footnote to something you already watched happen. Sharing the loud
|
||||
FACE with the milestone cards is right; sharing their SIZE made every footnote read as a milestone.
|
||||
|
||||
## Session log: nothing arrives unannounced (2026-08-11, same day)
|
||||
|
||||
Oliver's retest: *"the horde is not announced anymore"* and *"bosses are just there now"*. Both were
|
||||
true, and both were the same mistake — the announcement fired on the same frame as the thing it
|
||||
announced, so it was over before it registered.
|
||||
|
||||
- **The horde gets its breather back.** `warnHorde()` (beats.js) raises THEY KEEP COMING and holds
|
||||
an ordinary 'over' beat for `TUNE.hordeWarnT` (2.4 s); `startHorde()` runs when it expires. The
|
||||
cheat (`forceZombies`) still starts one instantly — it is a cheat.
|
||||
The breather runs on **its own clock** (`G.hordeWarn`, ticked in update above the 'over' block),
|
||||
deliberately NOT on the 'over' beat it also sets: any beat that moves the phase underneath it
|
||||
would strand the latch forever, which is the `mgT` lock this file already has a section about.
|
||||
`startHorde()` **returns a bool** now, and if the court has been taken when the warning expires
|
||||
the caller re-arms `pendingHorde` — the set gets its horde later rather than losing it silently.
|
||||
- **The chapter boss walks on behind an OVERLAY**, not a band card: the boss's name in `UI.bad` over
|
||||
`ENTERED THE COURT`. It is a modal (a boss stage is guaranteed calm — `startBossFight` clears the
|
||||
court two lines earlier, so this is on the sanctioned list) with the new `m.hold` self-dismiss
|
||||
clock, `TUNE.bossIntroT` = 3 s. A card in the routine-set slot and the routine-set size is why the
|
||||
biggest fight in the game read as the boss simply being there.
|
||||
- **The flamer does not trigger a horde** (his "vague feeling"). Arming any `kind: 'burst'` tin puts
|
||||
you in the same CONTROL MODE a horde does — racket auto-fires, the finger steers you absolutely,
|
||||
no serving — so a flamer or gun genuinely feels like a horde starting. Nothing in the weapon paths
|
||||
touches `startHorde`; with the horde announced again the two are told apart by the announcement.
|
||||
- Three tests added (15 total): the wave may not land on the frame of its own announcement, a mode
|
||||
that steals the court during the warning re-arms the latch, and the boss overlay names the boss
|
||||
and hands the court back without a tap.
|
||||
|
||||
## Session log: beats.js, the rename, and the build gate (2026-08-11, same day)
|
||||
|
||||
Oliver's structural question ("framework? smaller files?") answered with a deliberate NO on both —
|
||||
|
||||
Reference in new issue
Block a user