BUILDINGgame

felt.

Eight cue games in one offline HTML file: 8-ball to snooker and three-cushion, a CPU with personalities, a multi-season career. puttX's deterministic physics, extended to ball-on-ball.

CREATED OCT 24, 2026 · UPDATED OCT 29, 2026

PROBLEM

Pool on a phone is either a multiplayer storefront with a cue shop, or a toy whose balls do not behave like balls. Rules are reduced to 8-ball house rules, snooker is a separate app, and three-cushion does not exist.

HYPOTHESIS

puttX's sim already had what billiards needs: a fixed-step deterministic integrator, rolling and sliding friction, and a Node harness that replays any shot exactly. Add ball-ball contact, cushions, pockets and spin, and every cue game is a rules module over the same physics.

ARCHITECTURE

One index.html with no libraries and no network: CSS, markup and a script in seven sections, sim first. The sim region has no DOM, no Math.random and no clocks, and the live roll on screen calls the same strike and step functions the simulator does. A test asserts they agree byte for byte, so the page can never grow a second physics path.

Each table carries its own physics record (ball radius, rolling friction, cushion friction, rail restitution, spinning friction), and side spin decays at pooltool's measured rate. Cue elevation tilts the spin axis, so swerve and masse fall out of the model rather than being special-cased.

Rules are a registry. judge(game, result) never mutates the game; it hands the shot to the module for 8-ball, 9 and 10, 14.1, rotation, bumper pool, snooker (WPBSA rule numbers cited, free ball as pure geometry) or carom. The CPU searches shots on that same sim, shaped by personality knobs for risk, safety, look-ahead and noise. A career engine above it generates a seeded population, calendar, brackets, rankings and sponsors.

STACK

JavaScriptCanvasWeb AudioPlaywrightESLint

RESULT

Live on GitHub Pages and installable to the home screen. Eight games, three CPU levels plus career personalities, tutorials judged by the real rules, drills scored per shot, trick shots, a daily shot, replays, tournaments and pass-and-play for up to four. 137 commits since 2026-10-24, 66 of them on the second day.

MEASURED

metricvaluebaseline
games8 · 8, 9, 10, straight pool, rotation, bumper, snooker, three-cushion—
test suites26 · about 8 minutes, CPU matches and the stress suite dominate—
dependencies0—
shipped file1.07 MB · one index.html—
Math.random in the sim0 · seeded randomness only—

LEARNINGS

  • Byte-for-byte agreement between the live roll and the simulator is the one test that matters. Everything else, from the CPU to the tutorials, inherits its correctness from it.
  • Stored solutions are a physics regression test. Changing the cloth or the strike moves every trick shot, and re-solving them is how a physics change announces itself.
  • Layout checks are font-sensitive. A CI runner on DejaVu Sans is 7.5% wider than the iPhone's font and fails fit checks the phone passes; CI now measures with Inter.
  • A ball at rest can still be turning in place, so a shot does not end while anything spins. Real pool behaves that way, and the audit found turns that ended before it did.

PROVENANCE

Built from 2026-10-24 in Claude Code, on puttX's physics. The design is SPEC.md, the queue TASKS.md, and the artifact chain under .buildloop/, including the audit that every fix in audit-check cites.

TAGS

gamephysicsdeterministicbilliardsofflinepwazero-dependency