diffs / #45
feat(#45): neon signs on the arcade
Requested-by: demo replay (synthetic wallet)
+ BUILD+ UNIT TESTS+ LINT+ DIFF GATE+ PAGE CLASSIFIER+ PLAYWRIGHT
src/features/r45-neon-signs.jsNEW+19 −0
| 1 | +// #45: neon signs on the arcade building: an OPEN sign and a pizza slice sign on the rooftop walls. | ||
| 2 | +import { PAL } from "../palette.js"; | ||
| 3 | +const OPEN = ["0110111011101001", "1001101010001101", "1001111011101011", "1001100010001001", "0110100011101001"]; | ||
| 4 | +export default { | ||
| 5 | + id: "neon-signs-45", | ||
| 6 | + order: 26, | ||
| 7 | + layer: "mid", | ||
| 8 | + rooms: ["rooftop", "alley"], | ||
| 9 | + draw(g, w) { | ||
| 10 | + const on = w.reduced || Math.sin(w.t * 1.1 + 1) > -0.95; | ||
| 11 | + const ox = w.room === "alley" ? 150 : 158, oy = w.room === "alley" ? 60 : 120; | ||
| 12 | + g.fillStyle = PAL.ink; g.fillRect(ox - 3, oy - 3, 38, 16); | ||
| 13 | + for (let y = 0; y < 5; y++) for (let x = 0; x < 16; x++) if (OPEN[y][x] === "1") { g.fillStyle = on ? PAL.boss : PAL.winOff; g.fillRect(ox + x * 2, oy + y * 2, 2, 2); } | ||
| 14 | + const px = w.room === "alley" ? 210 : 60, py = w.room === "alley" ? 58 : 108; | ||
| 15 | + g.fillStyle = on ? PAL.pizza : PAL.winOff; | ||
| 16 | + for (let r = 0; r < 8; r++) g.fillRect(px + r, py + r, 12 - r * 2 + r, 1); | ||
| 17 | + g.fillStyle = on ? PAL.boss : PAL.winOff; g.fillRect(px + 4, py + 2, 2, 2); g.fillRect(px + 7, py + 4, 2, 2); | ||
| 18 | + }, | ||
| 19 | +}; |
1+// #45: neon signs on the arcade building: an OPEN sign and a pizza slice sign on the rooftop walls.
2+import { PAL } from "../palette.js";
3+const OPEN = ["0110111011101001", "1001101010001101", "1001111011101011", "1001100010001001", "0110100011101001"];
4+export default {
5+ id: "neon-signs-45",
6+ order: 26,
7+ layer: "mid",
8+ rooms: ["rooftop", "alley"],
9+ draw(g, w) {
10+ const on = w.reduced || Math.sin(w.t * 1.1 + 1) > -0.95;
11+ const ox = w.room === "alley" ? 150 : 158, oy = w.room === "alley" ? 60 : 120;
12+ g.fillStyle = PAL.ink; g.fillRect(ox - 3, oy - 3, 38, 16);
13+ for (let y = 0; y < 5; y++) for (let x = 0; x < 16; x++) if (OPEN[y][x] === "1") { g.fillStyle = on ? PAL.boss : PAL.winOff; g.fillRect(ox + x * 2, oy + y * 2, 2, 2); }
14+ const px = w.room === "alley" ? 210 : 60, py = w.room === "alley" ? 58 : 108;
15+ g.fillStyle = on ? PAL.pizza : PAL.winOff;
16+ for (let r = 0; r < 8; r++) g.fillRect(px + r, py + r, 12 - r * 2 + r, 1);
17+ g.fillStyle = on ? PAL.boss : PAL.winOff; g.fillRect(px + 4, py + 2, 2, 2); g.fillRect(px + 7, py + 4, 2, 2);
18+ },
19+};


CI log tail
$ ci:build (745 ms, exit 0) $ ci:test (204 ms, exit 0) TAP version 13 # Subtest: palette: valid hex, at most 40 colours ok 1 - palette: valid hex, at most 40 colours --- duration_ms: 0.978051 type: 'test' ... # Subtest: sprites: rectangular-ish rows of known keys ok 2 - sprites: rectangular-ish rows of known keys --- duration_ms: 10.239181 type: 'test' ... # Subtest: levels: every room has a name, platforms and a draw function ok 3 - levels: every room has a name, platforms and a draw function --- duration_ms: 4.214441 type: 'test' ... # Subtest: bosses: every file exports a class with update/draw ok 4 - bosses: every file exports a class with update/draw --- duration_ms: 0.920674 type: 'test' ... # Subtest: features: default export with a unique id and only known hooks ok 5 - features: default export with a unique id and only known hooks --- duration_ms: 3.787962 type: 'test' ... # Subtest: no network, storage or parent access anywhere in src ok 6 - no network, storage or parent access anywhere in src --- duration_ms: 4.163165 type: 'test' ... 1..6 # tests 6 # suites 0 # pass 6 # fail 0 # cancelled 0 # skipped 0 # todo 0 # duration_ms 128.576979 $ ci:lint (769 ms, exit 0) $ playwright 960x540 fps 60 long tasks 0 console errors 0