diffs / #3
feat(#3): the rooftop
Requested-by: SEED (built by us pre-launch)
+ BUILD+ UNIT TESTS+ LINT+ DIFF GATE+ PAGE CLASSIFIER+ PLAYWRIGHT
src/levels/rooftop.jsNEW+37 −0
| 1 | +// Seed #3: the rooftop. The cat starts on the left roof, a water tower stands on the right roof. | ||
| 2 | +// Roof tops are one-way platforms. The door on the left roof leads down to the lobby; walk off the left edge for the alley. | ||
| 3 | +import { PAL } from "../palette.js"; | ||
| 4 | +import { blit } from "../sprites.js"; | ||
| 5 | + | ||
| 6 | +const BLOCKS = [ | ||
| 7 | + { x: 0, y: 96, w: 80, h: 84, rows: 5 }, | ||
| 8 | + { x: 86, y: 128, w: 62, h: 52, rows: 3 }, | ||
| 9 | + { x: 154, y: 114, w: 60, h: 66, rows: 4 }, | ||
| 10 | + { x: 222, y: 92, w: 98, h: 88, rows: 5 }, | ||
| 11 | +]; | ||
| 12 | + | ||
| 13 | +export default { | ||
| 14 | + name: "rooftop", | ||
| 15 | + label: "rooftop", | ||
| 16 | + platforms: BLOCKS.map((b) => ({ x: b.x, y: b.y, w: b.w })), | ||
| 17 | + start: { x: 30, y: 90 }, | ||
| 18 | + bossAt: { x: 262, y: 92 }, | ||
| 19 | + exits: { left: { to: "alley", at: { x: 300, y: 150 } } }, | ||
| 20 | + doors: [{ x: 52, y: 84, to: "lobby", at: { x: 40, y: 150 } }], | ||
| 21 | + boss: null, | ||
| 22 | + spawn: [], | ||
| 23 | + music: "rooftop-a", | ||
| 24 | + draw(g) { | ||
| 25 | + for (const b of BLOCKS) { | ||
| 26 | + g.fillStyle = PAL.wall; g.fillRect(b.x, b.y, b.w, b.h); | ||
| 27 | + g.fillStyle = PAL.roof; g.fillRect(b.x - 1, b.y, b.w + 2, 4); | ||
| 28 | + g.fillStyle = PAL.ink; g.fillRect(b.x - 1, b.y + 4, b.w + 2, 1); | ||
| 29 | + let i = (b.x * 7) % 5; | ||
| 30 | + for (let r = 0; r < b.rows; r++) for (let x = b.x + 8; x < b.x + b.w - 8; x += 14) { | ||
| 31 | + i++; g.fillStyle = i % 3 === 0 ? PAL.winOff : PAL.light; | ||
| 32 | + g.fillRect(x, b.y + 12 + r * 16, 7, 9); g.fillStyle = PAL.ink; g.fillRect(x + 3, b.y + 12 + r * 16, 1, 9); | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | + blit(g, "tower", 282, 70); | ||
| 36 | + }, | ||
| 37 | +}; |
1+// Seed #3: the rooftop. The cat starts on the left roof, a water tower stands on the right roof.
2+// Roof tops are one-way platforms. The door on the left roof leads down to the lobby; walk off the left edge for the alley.
3+import { PAL } from "../palette.js";
4+import { blit } from "../sprites.js";
5+
6+const BLOCKS = [
7+ { x: 0, y: 96, w: 80, h: 84, rows: 5 },
8+ { x: 86, y: 128, w: 62, h: 52, rows: 3 },
9+ { x: 154, y: 114, w: 60, h: 66, rows: 4 },
10+ { x: 222, y: 92, w: 98, h: 88, rows: 5 },
11+];
12+
13+export default {
14+ name: "rooftop",
15+ label: "rooftop",
16+ platforms: BLOCKS.map((b) => ({ x: b.x, y: b.y, w: b.w })),
17+ start: { x: 30, y: 90 },
18+ bossAt: { x: 262, y: 92 },
19+ exits: { left: { to: "alley", at: { x: 300, y: 150 } } },
20+ doors: [{ x: 52, y: 84, to: "lobby", at: { x: 40, y: 150 } }],
21+ boss: null,
22+ spawn: [],
23+ music: "rooftop-a",
24+ draw(g) {
25+ for (const b of BLOCKS) {
26+ g.fillStyle = PAL.wall; g.fillRect(b.x, b.y, b.w, b.h);
27+ g.fillStyle = PAL.roof; g.fillRect(b.x - 1, b.y, b.w + 2, 4);
28+ g.fillStyle = PAL.ink; g.fillRect(b.x - 1, b.y + 4, b.w + 2, 1);
29+ let i = (b.x * 7) % 5;
30+ for (let r = 0; r < b.rows; r++) for (let x = b.x + 8; x < b.x + b.w - 8; x += 14) {
31+ i++; g.fillStyle = i % 3 === 0 ? PAL.winOff : PAL.light;
32+ g.fillRect(x, b.y + 12 + r * 16, 7, 9); g.fillStyle = PAL.ink; g.fillRect(x + 3, b.y + 12 + r * 16, 1, 9);
33+ }
34+ }
35+ blit(g, "tower", 282, 70);
36+ },
37+};


CI log tail
$ ci:build (604 ms, exit 0) $ ci:test (154 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.992769 type: 'test' ... # Subtest: sprites: rectangular-ish rows of known keys ok 2 - sprites: rectangular-ish rows of known keys --- duration_ms: 2.273006 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: 1.954189 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.652021 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: 1.00936 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: 0.7374 type: 'test' ... 1..6 # tests 6 # suites 0 # pass 6 # fail 0 # cancelled 0 # skipped 0 # todo 0 # duration_ms 92.27021 $ ci:lint (798 ms, exit 0) $ playwright 960x540 fps 60 long tasks 0 console errors 0