Credibility pass: the seams get sanded

Scoped to everything since the last pass (3308850). Three blind
reviews, every finding verified before touching anything.

Confirmed and fixed: two identical comment-splitting insertions left
doc comments orphaned from their fields (net and local alike); a
51-line CSS fossil of the pre-extraction inline effects survived in
Board.svelte; the rev-13 miss-roll test asserted tautologies while
its comment claimed a check the code never made — it now proves the
die was consumed, and the skeleton is no longer returned as trollId;
the sprite registry's `as never` silently disabled the completeness
its annotation advertised (now a mapped type, one cast at the
dispatch seam); a dead ternary guarded a union that doesn't exist;
Bolt carried a duplicate .fork rule from a color iteration; fxTtl
contradicted three sprites' real animation lengths; the permanence
sentinel was reinvented as a magic 9000 (the engine now exports
isPermanentDuration); CELL was declared thrice (fx.ts now imports
it); App and Replay ran two divergent fx schedulers (one scheduleFx
now, cancellable — stale flourishes can no longer fire after leaving
a game); TokenArt retried missing files forever; the anti-anti
escape guards merge with the gate asymmetry explained; wall-of-fire's
rev-12 carve-out is marked; overLimit ignored a displayed BRAINSTONE
(bots over-discarded by two); botRemark's header mis-stated its own
branches; deliverGold fired on any drop, not a home-base delivery;
escape and win banter never fired from the steps that carry them.

Rejected: "as a human would" (house voice); FxGallery's dev-harness
framing (trimmed one plea, kept the facts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-17 12:12:03 -04:00
co-authored by Claude Fable 5
parent 4528c66057
commit d2b40ec6f8
16 changed files with 116 additions and 130 deletions
+18 -12
View File
@@ -7,10 +7,10 @@
import Help from "./Help.svelte";
import Replay from "./Replay.svelte";
import FxGallery from "./FxGallery.svelte";
import { fxForEvents, fxTtl, type BoardFx } from "./fx";
import { scheduleFx, type BoardFx } from "./fx";
import { CREATURE_ART, objectArt, TERRAIN_ART, tokenArt } from "./art";
import { local } from "./local.svelte";
import { allCardDefs, cardDef, isNumberCard, SIDES, stepTarget, cellKey, isMovableObject, sightedCellsFor, type GameView, eligibleCellsFor } from "@wizwar/engine";
import { allCardDefs, cardDef, isNumberCard, isPermanentDuration, SIDES, stepTarget, cellKey, isMovableObject, sightedCellsFor, type GameView, eligibleCellsFor } from "@wizwar/engine";
import type { CardInstance, Side } from "@wizwar/engine";
net.connect();
@@ -37,22 +37,28 @@
localStorage.setItem("wizwar-no-fanfare", announce ? "0" : "1");
}
/** Which pending attack the player has already acknowledged (modal dismissed). */
const fxWorkshop = new URLSearchParams(location.search).has("fx");
let attackNoticeSeen = $state<string | null>(null);
/** Live spell flourishes on the board (cosmetic, self-expiring). */
let boardFx = $state<BoardFx[]>([]);
function playFx(events: Parameters<typeof fxForEvents>[0]) {
let fxCancels: (() => void)[] = [];
function playFx(events: Parameters<typeof scheduleFx>[0]) {
if (!view) return;
for (const { fx, delay } of fxForEvents(events, view)) {
setTimeout(() => {
boardFx = [...boardFx, fx];
setTimeout(() => (boardFx = boardFx.filter((f) => f.id !== fx.id)), fxTtl(fx.kind));
}, delay);
}
fxCancels.push(scheduleFx(
events, view,
(fx) => (boardFx = [...boardFx, fx]),
(id) => (boardFx = boardFx.filter((f) => f.id !== id)),
));
}
$effect(() => {
net.onFx = playFx;
local.onFx = playFx;
return () => { net.onFx = null; local.onFx = null; };
return () => {
net.onFx = null;
local.onFx = null;
fxCancels.forEach((c) => c());
fxCancels = [];
};
});
const openingRolls = $derived(net.openingRolls ?? local.openingRolls);
function dismissRolls() {
@@ -906,7 +912,7 @@
}
</script>
{#if new URLSearchParams(location.search).has("fx")}
{#if fxWorkshop}
<FxGallery />
{:else}
<div class="table">
@@ -1413,7 +1419,7 @@
peekCard = { instanceId: `peek-${e.id}`, cardId: e.cardId };
peekCreatureId = null;
}}>
✦ {spellName(e.cardId)}{e.remainingTurns < 9000 ? ` · ${e.remainingTurns}` : ""}
✦ {spellName(e.cardId)}{isPermanentDuration(e.remainingTurns) ? "" : ` · ${e.remainingTurns}`}
</button>
{/each}
</div>