diffs / #2

feat(#2): the cat

SHIPPED commit f6a31e0 +26 −0 request “a white pixel cat to play” SEED · built by us pre-launch

Requested-by: SEED (built by us pre-launch)
+ BUILD+ UNIT TESTS+ LINT+ DIFF GATE+ PAGE CLASSIFIER+ PLAYWRIGHT
src/player.jsNEW+26 −0
1+// Seed #2: the white pixel cat. Arrows/WASD to move, Space/Up to jump, E/Down at a door.
2+import { blit } from "./sprites.js";
3+import { solidBelow } from "./world.js";
4+export const SPEED = 82, JUMP = 205, GRAV = 560;
5+export function makePlayer() {
6+ return {
7+ x: 24, y: 40, vx: 0, vy: 0, f: 1, onGround: false, walk: 0, emote: null, emoteT: 0, jumps: 1,
8+ update(dt, w, input) {
9+ const dir = (input.held("right") ? 1 : 0) - (input.held("left") ? 1 : 0);
10+ this.vx = dir * SPEED; if (dir) this.f = dir;
11+ this.walk = dir && this.onGround ? this.walk + dt : 0;
12+ if (input.take("jump") && (this.onGround || this.jumpsLeft > 0)) { if (!this.onGround) this.jumpsLeft--; this.vy = -JUMP; this.onGround = false; }
13+ for (let i = 0; i < 4; i++) if (input.take("e" + i)) { this.emote = i; this.emoteT = 2; }
14+ this.emoteT = Math.max(0, this.emoteT - dt); if (!this.emoteT) this.emote = null;
15+ this.vy = Math.min(320, this.vy + GRAV * dt);
16+ const ny = this.y + this.vy * dt;
17+ const floor = this.vy >= 0 ? solidBelow(w.level, this.x, this.y - 0.01, ny) : null;
18+ if (floor != null) { this.y = floor; this.vy = 0; this.onGround = true; this.jumpsLeft = this.jumps - 1; } else { this.y = ny; this.onGround = false; }
19+ this.x += this.vx * dt;
20+ },
21+ draw(g) {
22+ blit(g, Math.floor(this.walk * 8) % 2 ? "catWalk" : "cat", this.x - 6, this.y - 11, this.f < 0);
23+ if (this.emote != null) blit(g, ["heart", "wave", "bang", "ask"][this.emote], this.x - 2, this.y - 19);
24+ },
25+ };
26+}
1+// Seed #2: the white pixel cat. Arrows/WASD to move, Space/Up to jump, E/Down at a door.
2+import { blit } from "./sprites.js";
3+import { solidBelow } from "./world.js";
4+export const SPEED = 82, JUMP = 205, GRAV = 560;
5+export function makePlayer() {
6+ return {
7+ x: 24, y: 40, vx: 0, vy: 0, f: 1, onGround: false, walk: 0, emote: null, emoteT: 0, jumps: 1,
8+ update(dt, w, input) {
9+ const dir = (input.held("right") ? 1 : 0) - (input.held("left") ? 1 : 0);
10+ this.vx = dir * SPEED; if (dir) this.f = dir;
11+ this.walk = dir && this.onGround ? this.walk + dt : 0;
12+ if (input.take("jump") && (this.onGround || this.jumpsLeft > 0)) { if (!this.onGround) this.jumpsLeft--; this.vy = -JUMP; this.onGround = false; }
13+ for (let i = 0; i < 4; i++) if (input.take("e" + i)) { this.emote = i; this.emoteT = 2; }
14+ this.emoteT = Math.max(0, this.emoteT - dt); if (!this.emoteT) this.emote = null;
15+ this.vy = Math.min(320, this.vy + GRAV * dt);
16+ const ny = this.y + this.vy * dt;
17+ const floor = this.vy >= 0 ? solidBelow(w.level, this.x, this.y - 0.01, ny) : null;
18+ if (floor != null) { this.y = floor; this.vy = 0; this.onGround = true; this.jumpsLeft = this.jumps - 1; } else { this.y = ny; this.onGround = false; }
19+ this.x += this.vx * dt;
20+ },
21+ draw(g) {
22+ blit(g, Math.floor(this.walk * 8) % 2 ? "catWalk" : "cat", this.x - 6, this.y - 11, this.f < 0);
23+ if (this.emote != null) blit(g, ["heart", "wave", "bang", "ask"][this.emote], this.x - 2, this.y - 19);
24+ },
25+ };
26+}
Before
BEFORE
After
AFTER
CI log tail
$ ci:build  (850 ms, exit 0)

$ ci:test  (165 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.925623
  type: 'test'
  ...
# Subtest: sprites: rectangular-ish rows of known keys
ok 2 - sprites: rectangular-ish rows of known keys
  ---
  duration_ms: 1.252025
  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.209405
  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: 3.314907
  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.5381
  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: 1.040648
  type: 'test'
  ...
1..6
# tests 6
# suites 0
# pass 6
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 99.213971

$ ci:lint  (493 ms, exit 0)

$ playwright 960x540  fps 60  long tasks 0  console errors 0