diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59355c8..da2ca95 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -176,6 +176,19 @@ jobs: echo "::error file=docs/war.gif::committed docs/war.gif is stale; rerun \`node tests/emulator/record_gif.mjs war 360 2 docs/war.gif 4\` and commit the new gif" exit 1 fi + - name: Verify docs/pong.gif is up to date + # Same contract as the platformer and war gifs: the README + # embeds docs/pong.gif as the third project demo. Pong's + # title screen (CPU VS CPU / 1 PLAYER / 2 PLAYERS menu) is + # the gif thumbnail, so warmup = 4 keeps it in frame before + # the autopilot advances to gameplay. + working-directory: tests/emulator + run: | + node record_gif.mjs pong 360 2 /tmp/pong.gif 4 + if ! cmp -s ../../docs/pong.gif /tmp/pong.gif; then + echo "::error file=docs/pong.gif::committed docs/pong.gif is stale; rerun \`node tests/emulator/record_gif.mjs pong 360 2 docs/pong.gif 4\` and commit the new gif" + exit 1 + fi - name: Upload actual + diff PNGs on failure if: failure() uses: actions/upload-artifact@v4 diff --git a/CLAUDE.md b/CLAUDE.md index 40ef459..8fe317f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,28 +22,31 @@ re-derive the project conventions from scratch. tmp path and fails if the committed version differs, pointing at the exact `cargo run -- build examples/.ne` to run. The pre-commit hook under `scripts/pre-commit` catches this locally. -- **`docs/platformer.gif` and `docs/war.gif` are committed** and - embedded in the top-level README as the project demos. `gifenc` + - `jsnes` are deterministic, so each gif's bytes are a function of - the compiler, the runtime, the harness, and the underlying `.ne` - source(s). Any change to those that affects the first ~6 seconds - of observable gameplay must be followed by regenerating the - affected gif: +- **`docs/platformer.gif`, `docs/war.gif`, and `docs/pong.gif` are + committed** and embedded in the top-level README as the project + demos. `gifenc` + `jsnes` are deterministic, so each gif's bytes + are a function of the compiler, the runtime, the harness, and + the underlying `.ne` source(s). Any change to those that affects + the first ~6 seconds of observable gameplay must be followed by + regenerating the affected gif: ```bash node tests/emulator/record_gif.mjs platformer 360 2 docs/platformer.gif node tests/emulator/record_gif.mjs war 360 2 docs/war.gif 4 + node tests/emulator/record_gif.mjs pong 360 2 docs/pong.gif 4 ``` - (The trailing `4` on the war command is the warmup-frames - override — war's title menu is the gif thumbnail, so we don't - skip past it the way the platformer recording does.) Commit the - regenerated gif in the same change. CI's `emulator` job renders - fresh gifs and fails if either committed copy doesn't byte-match. - The pre-commit hook rebuilds whichever gif is affected when - `platformer.ne`, `platformer.nes`, any file under `examples/war/`, - `war.ne`, `war.nes`, `record_gif.mjs`, or `harness.html` is - staged (and `tests/emulator/node_modules` is installed). + (The trailing `4` on the war and pong commands is the + warmup-frames override — both open on a title menu that we want + as the gif thumbnail, so we don't skip past it the way the + platformer recording does.) Commit the regenerated gif in the + same change. CI's `emulator` job renders fresh gifs and fails if + any committed copy doesn't byte-match. The pre-commit hook + rebuilds whichever gif is affected when `platformer.ne`, + `platformer.nes`, any file under `examples/war/`, `war.ne`, + `war.nes`, any file under `examples/pong/`, `pong.ne`, + `pong.nes`, `record_gif.mjs`, or `harness.html` is staged (and + `tests/emulator/node_modules` is installed). - `docs/future-work.md` lists the remaining gaps. If you implement something from that file, update the doc in the same PR. diff --git a/README.md b/README.md index 4ce0c97..99027cf 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,10 @@ _Source: [`examples/platformer.ne`](examples/platformer.ne)_ _Source: [`examples/war.ne`](examples/war.ne)_ +![Pong demo](docs/pong.gif) + +_Source: [`examples/pong.ne`](examples/pong.ne)_ + ## Quick Start ```bash diff --git a/docs/pong.gif b/docs/pong.gif new file mode 100644 index 0000000..652cd7e Binary files /dev/null and b/docs/pong.gif differ diff --git a/scripts/pre-commit b/scripts/pre-commit index 2b73842..5a5070e 100755 --- a/scripts/pre-commit +++ b/scripts/pre-commit @@ -86,4 +86,9 @@ if [ $recorder_or_harness_changed -eq 1 ] || \ check_gif war 4 || exit 1 fi +if [ $recorder_or_harness_changed -eq 1 ] || \ + echo "$changed_files" | grep -qE '^examples/pong(\.(ne|nes)|/[^/]+\.ne)$'; then + check_gif pong 4 || exit 1 +fi + echo "All pre-commit checks passed." diff --git a/tests/emulator/record_gif.mjs b/tests/emulator/record_gif.mjs index bc38a72..1abdc8a 100644 --- a/tests/emulator/record_gif.mjs +++ b/tests/emulator/record_gif.mjs @@ -6,6 +6,7 @@ // Examples: // node record_gif.mjs platformer 360 2 docs/platformer.gif // node record_gif.mjs war 360 2 docs/war.gif 4 +// node record_gif.mjs pong 360 2 docs/pong.gif 4 // // The recorder drives `harness.html` via puppeteer, collects one // canvas frame every `stride` NES frames for `frames` total, and @@ -20,14 +21,15 @@ // recording uses 4 instead because that demo opens on its menu and // we want the title screen to be the gif's thumbnail. // -// IMPORTANT: `docs/platformer.gif` and `docs/war.gif` are committed -// and embedded in the README. Any change to the compiler, the -// runtime, the harness, or the underlying `.ne` source that alters -// the gameplay you see in the first ~6 seconds of either demo must -// be followed by +// IMPORTANT: `docs/platformer.gif`, `docs/war.gif`, and +// `docs/pong.gif` are committed and embedded in the README. Any +// change to the compiler, the runtime, the harness, or the +// underlying `.ne` source that alters the gameplay you see in the +// first ~6 seconds of any of the three demos must be followed by // // node tests/emulator/record_gif.mjs platformer 360 2 docs/platformer.gif // node tests/emulator/record_gif.mjs war 360 2 docs/war.gif 4 +// node tests/emulator/record_gif.mjs pong 360 2 docs/pong.gif 4 // // committed alongside the source change. The CI `emulator` job // regenerates both gifs and fails if the committed copies are stale —