Thanks for fishing around in here! Nethook is a small, dependency-free Node project and contributions are very welcome — especially new Spot Packs, extra species, reel-minigame ideas, and procedural-generation tweaks.
git clone https://github.com/ClickClickMedia/Nethook && cd Nethook
npm test # node game/selftest.mjs — should print "OK — N assertions passed."
node game/index.mjs # play the procedural lake (needs a real terminal)
node game/index.mjs "Lake Taupō" # …or a built-in spot
node game/launch.mjs --dry-run # show the new-window spawn plan for your env
node game/packcheck.mjs <pack.json> # validate a Spot PackNo build step, no npm install (zero runtime dependencies), Node ≥ 18.
The game logic is split so it's testable without a terminal, and that separation
is the project's backbone. Please preserve it (see CLAUDE.md for the
full architecture):
game/core.mjs,world.mjs,render.mjs,pack.mjs,solunar.mjsare pure — nofs, noprocess.stdout, no timers, noDate.now()inside reducers.- All randomness goes through
game/rng.mjsagainststate.rngStateso runs are reproducible and the headless tests stay deterministic. Don't callMath.random(). - All terminal/disk I/O lives in
game/index.mjs(and the small hook/launch scripts). If you need a new input (a clock, a file), read it there and pass it into an action — never reach for it inside the core. - Never trust a Spot Pack — route every pack through
validatePack()inpack.mjs; sanitize, don't reject, where reasonable. - Zero runtime dependencies. Please don't add any to ship the game.
- A new Spot Pack — a JSON file in
game/packs/for a real lake/river/coast. See the schema incommands/spot.mdand the three existing packs. Runnode game/packcheck.mjs game/packs/your-pack.jsonand add a line to the selftest's "built-in packs" expectation if you like. Real species, tackle, and the optionaltime/season/weather/bait/tempOptimumgates earn bonus points for authenticity. - A built-in species — append to
BUILTIN_SPECIESingame/fish.mjs. - A reel-minigame variant — add a mode in
core.mjs(chooseReelMode+ a*Reelreducer) and render it inrender.mjs.
Because the core is pure, prefer adding assertions to game/selftest.mjs (drive
step() with a fixed seed and scripted actions) over manual play. npm test
must stay green, and new behaviour should come with new assertions.
- Fork, branch, and make your change.
- Run
npm test(green) and, for plugin changes,claude plugin validate .. - Match the existing code style (plain ESM, 2-space indent, semicolons — mirror the surrounding file).
- Open a PR describing what and why; the template will prompt you.
By contributing you agree your work is licensed under the repo's MIT License.