An open-source billiards simulator that runs in the browser
This is a free, open-source billiards and pool physics simulator written in TypeScript. It runs in any modern desktop or mobile browser with nothing to install and no account to create — open a page and play, practise, analyse shots or explore how billiards physics works. Behind it is a small physics engine built from published work on ball motion, collisions and cushion impacts, and the table is drawn in 3D with WebGL and three.js.
The project began in 2018 and has been developed in public ever since, mostly on a Raspberry Pi 4. It is maintained by an independent developer, not a studio, and contributions are welcome.
Explore
A few pages worth knowing about, depending on what you came for.
- Shot sensitivity analysis & training — explore how variations in aim, spin, power and elevation affect results.
- Three-cushion physics — tune the cushion constants and watch the models respond.
- Interactive physics diagrams — the published models recreated as live figures.
- Practice table and three-cushion exam — set up shots, then grade your level of play.
- Nine-ball, 8-ball and snooker — the main game modes.
- Research and references — the papers the simulation is built from.
What you can play
Five rule sets share the same tables and physics, so you can move between them without changing anything on your device.
- Nine-ball — the fast rotation game. Practice mode lets you build a layout and share a replay link of a break with whoever you like.
- 8-ball — solids and stripes, with a Hi-Res rendering mode.
- Snooker — full-size 12-foot tables with 15 reds, plus shorter games on a 6-foot table.
- Three-cushion carom — the discipline the cushion model has been tuned hardest against. A beginner mode is available, and drills can be set up in practice.
- Sagu — the Korean four-ball carom game, also playable on a small 5-foot table.
Two practice bots, ClawBreak and TheFarJaw, will play you when nobody else is around, and a speedrun challenge races you against the clock. The reveal game uses straight pool potting to uncover hidden pictures.
Practice and the three-cushion exam
For deliberate billiards practice, the practice table lets you set up any shot or position and repeat it, with no opponent and no clock. When you want to measure progress rather than just practise, the three-cushion exam works through a graded list of three-cushion billiards shots and marks each attempt, reporting an assessment level, completion and score. It stays an exam on purpose, but it is also this project's structured training: accuracy, cue-ball control, positional play and consistency all count towards the result.
How the physics works
The engine is deliberately lightweight and deterministic rather than exhaustive; the project's own README calls the physics “unsophisticated”. The intention is to model the effects a player actually notices — spin, throw, and how the ball leaves a cushion — and each of those behaviours follows a specific published model that acts as its reference, rather than being tuned by feel until it looks realistic.
Ball motion follows Han (2005) with corrections noted by Kiefl; ball-to-ball collisions follow Alciatore, including the small throw effect caused by friction between the balls; cushion impacts use Mathavan (2010) by default, with the analytical compliant-cushion model from Stronge's Impact Mechanics available as an alternative.
Ball motion on the cloth
The engine tracks the ball's velocity and angular velocity, and the relative velocity at the point where the ball touches the cloth tells it whether the ball is sliding or rolling. That surface velocity is built from linear velocity and spin:
While contact is slipping, friction opposes the slip direction and slows both the ball and its spin:
Once contact rolls, a smaller deceleration sets in, and the ball curves as spin carries it off line:
Ball-to-ball collisions
On contact, a normal impulse separates the balls and a tangential impulse applies the throw effect. For the striking ball:
Ball-to-cushion collisions
Cushion behaviour is the hardest part to get right. Play uses the numerical model from Mathavan (2010) by default: the compression and restitution phases are solved step by step, tracking slip at both the cushion contact point \(I\) and the cloth contact point \(C\). At the cushion that slip velocity is the surface velocity there:
The slip direction at each contact \(\phi\) (cushion) and \(\phi'\) (cloth), together with its magnitude \(s\), sets the friction acting over each increment of normal impulse \(\Delta P_I\), which is what advances the centroid velocity through the collision:
Compression iterates until the ball stops approaching the cushion (\(\dot{v}_y \le 0\)); restitution continues until the work done on the cushion reaches \(e_e^2\) times the work done in compression. Equations the paper leaves out had to be inferred to close that numerical solution; that is documented rather than hidden.
The Stronge compliant cushion model
The engine can instead use the analytical compliant-cushion model from
Stronge's Impact Mechanics, selectable on the
three-cushion physics page or with
cushionModel=stronge in the URL. There the contact
velocity is simply the velocity at the cushion contact point:
The Stronge solution then classifies the impact into one of three slip regimes before reconstructing the outgoing velocity:
| Regime | Condition |
|---|---|
| Gross slip | High tangential-to-normal velocity ratio |
| Initial stick | Low tangential-to-normal velocity ratio |
| Slip–stick–slip | Between the two — the contact sticks, then slips again |
Both models can be inspected and re-tuned yourself: the three-cushion physics page exposes the constants, and the Mathavan and Stronge diagram pages recreate figures from the papers to check the code against them.
Features
- Backspin, sidespin and cushion bounces are modelled.
- Presentation uses WebGL in any modern browser on mobile, Linux, Mac or Windows.
- Breaks can be recorded and played back.
- A two-player online mode served by an nchan nginx server, with public lobbies.
- Nine-ball, 8-ball, snooker, three-cushion and Sagu (four-ball) rules.
- Aim, spin, power, elevation and camera are all reachable by mouse, trackpad, touch or keyboard; press H in-game for the full control list.
- Deploys to GitHub Pages, Vercel and Render through GitHub Actions.
- Runs on modest hardware — it was developed mostly on a Raspberry Pi 4.
Playing against other people
The lobby lists who is online so you can challenge someone directly; the session runs over a public nchan server. There is also a two-tab mode for playing across two windows on one machine, and hourly arenas in the style of lichess, where you try to win as many games as possible in half an hour.
Long-running progress is tracked outside the game: the highest breaks go to a leaderboard on Vercel, and rated games contribute to an ELO rating using Glicko2. If you would rather not play in a browser at all, thin client wrappers are published for Windows, macOS and Linux and for Android.
Open source and licence
The project is open source under the GNU General Public License — the full text is in the LICENSE file. The code lives at github.com/tailuge/billiards and contributions are welcome, whether that is a bug, a physics tweak, a translation or a new rule set.
Local development uses Node and Yarn: yarn install,
yarn build, then yarn serve to play at
localhost:8080. yarn test runs the Jest
suite and yarn coverage reports on it. The README in
the repository has the up-to-date commands and the exact tool
versions.
Development and technology
The simulation itself is plain TypeScript with no engine dependency; three.js handles the 3D rendering. Because the engine is deterministic and light, a single run can be rolled forward thousands of times — about 500 rollouts per second on four CPU cores — which makes it usable for shot analysis and optimisation as well as play.
Those rollouts run either in the browser through Web Workers or headlessly under Node.js. That is what supports multi-shot parameter fitting, physics optimiser runs, and calibration against recorded real-world trajectories for friction, spin decay, restitution and cushion deflection. The worker and simulation research page documents the protocol and the runtime parameter overrides.
Research and references
The models implemented here are not presented as new research; each is a published model used as the reference for that part of the engine, with validation figures kept alongside the code so the results can be compared with the papers.
- Han (2005) — ball mechanics, with Kiefl's corrections. Surface velocity, sliding and rolling.
- Alciatore — collision impulse and throw.
- Mathavan (2010) — ball–cushion interaction, the model used by default in play and recreated in the model validation diagrams.
- Stronge, Impact Mechanics — the analytical compliant cushion model, selectable as an alternative, with its own diagram page.
- Maximum spin — limits on how much spin a cue can impart.
Two forks have taken the simulation in their own directions: a three-cushion trainer with sensitivity analysis and an Italian five-pin game. The writing covers how the physics feels and how the models were implemented, in more depth for the cushion work.
More
Everything else the project ships, in one place.
Play and practise
- Play in the browser
- Online lobby
- Practice table
- Hourly arenas
- Speedrun challenge
- Billiards exam
- Picture-reveal game
- Two-player, two tabs
- Customise your cue
- Customise your emblem
Physics and analysis
- Interactive shot analysis & training
- Interactive physics diagrams
- Three-cushion physics page — tune the constants yourself
- Mathavan model validation
- Stronge cushion model
- Three-cushion diamond system
- Nine-ball shot diagrams
- Export shot diagrams as SVG or PNG
- Web Worker simulation research
- Physics optimiser
- Multi-shot parameter fitting
Writing
- Why most pool games feel wrong
- Clearing the line-up — practice log
- Implementing Mathavan cushion physics
- Snooker and three-cushion notes