FEAR stains the forbidden ground in the cockpit too

The aura's warp-walking diamond — dreadDistance ≤ 3, extracted to one
shared fearCells so the board's dashed ring, the cockpit's floor stain,
and the engine's refusal can never disagree — now tints the flagstones
violet in first person, breathing like the board's aura, beneath the
dread ring already at the bearer's feet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
Eric Wagoner
2026-09-01 12:06:00 -04:00
co-authored by Claude Fable 5
parent 203b6101bd
commit 19888f9e84
3 changed files with 51 additions and 15 deletions
+31 -1
View File
@@ -9,7 +9,8 @@
import { terrainFallback, TERRAIN3D } from "./terrain3d";
import { tokenArt } from "../art";
import { PLAYER_COLORS } from "../colors";
import type { GameView } from "@wizwar/engine";
import { fearCells } from "@wizwar/engine";
import type { GameView } from "@wizwar/engine";
let {
view,
@@ -120,6 +121,23 @@
}
return px;
}
// The dread-stained squares, rasterized once per view (null = no fear).
const dreadCache = new WeakMap<object, Uint8Array | null>();
function dreadGridOf(v: GameView): Uint8Array | null {
if (dreadCache.has(v)) return dreadCache.get(v)!;
const cells = fearCells(v);
let grid: Uint8Array | null = null;
if (cells.size > 0) {
grid = new Uint8Array(v.board.width * v.board.height);
for (const k of cells) {
const [fx, fy] = k.split(",").map(Number) as [number, number];
if (fx >= 0 && fy >= 0 && fx < v.board.width && fy < v.board.height) grid[fy * v.board.width + fx] = 1;
}
}
dreadCache.set(v, grid);
return grid;
}
let frame: ImageData | null = null;
// The floor wears decals: home emblems in their owners' colors, pits
@@ -222,6 +240,10 @@
if (lx >= 0 && ly >= 0 && lx < litBw && ly < litBh) litGrid[ly * litBw + lx] = 1;
}
}
// FEAR's aura stains the forbidden ground itself, as the board draws
// its dashed diamond — the same warp-walking yardstick behind both.
const dreadGrid = dreadGridOf(view);
const dreadBlend = dreadGrid ? 0.16 + 0.07 * Math.sin(time / 400) : 0;
for (let row = 0; row < H; row++) {
const below = row > half;
const dz = below ? row - half : half - row;
@@ -260,6 +282,14 @@
const gx = (wx - u) | 0, gy = (wy - v) | 0;
if (gx < 0 || gy < 0 || gx >= litBw || gy >= litBh || !litGrid[gy * litBw + gx]) sh *= 0.3;
}
if (dreadGrid && below) {
const gx = (wx - u) | 0, gy = (wy - v) | 0;
if (gx >= 0 && gy >= 0 && gx < litBw && gy < litBh && dreadGrid[gy * litBw + gx]) {
r = r * (1 - dreadBlend) + 122 * dreadBlend;
g = g * (1 - dreadBlend) + 74 * dreadBlend;
b = b * (1 - dreadBlend) + 138 * dreadBlend;
}
}
if (dec) {
const hx = (wx - u) | 0, hy = (wy - v) | 0;
if (hx >= 0 && hy >= 0 && hx < dec.bw && hy < dec.bh) {