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
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
| metric | value | baseline |
|---|---|---|
| games | 8 · 8, 9, 10, straight pool, rotation, bumper, snooker, three-cushion | — |
| test suites | 26 · about 8 minutes, CPU matches and the stress suite dominate | — |
| dependencies | 0 | — |
| shipped file | 1.07 MB · one index.html | — |
| Math.random in the sim | 0 · 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.