BilliardRack
Racks fifteen balls from a pool, and racks them again on R.
What it does
When its pool is ready, the rack takes fifteen balls from it and numbers them in 8-ball order: the 1 on the apex, the 8 in the middle of the third row, a solid and a stripe in the two back corners. It stops them, turns each so its number is on top, and lays them out in a tight triangle with the apex on the table's foot spot. Every ball touches its neighbours.
It also puts the cue ball (the BilliardBall numbered 0) back on the head spot.
Press R, or send billiards.rack.request, and it racks again. Balls still on the table go back to the pool first, and potted ones come back with them.
Use it in a scene
A scene is just data — a list of entities, each with its components. At startup the SceneLoader turns this JSON into a live world; edit the file and reload to rebuild it.
Build it from scratch with the bjs CLI:
- 1Scaffold a project
World, renderer, and dev server — ready to run.
- 2Install dependencies
- 3Add BilliardRack
Copies its source into src/ so the scene resolves.
First time? Run bjs login once.
- 4Paste the scene into src/scenes/arcade-room.ts and run
SceneLoader builds the world from the JSON; reload to rebuild.
The Balls entity is the pool's blueprint. The rack numbers each ball as it takes it out.
Props
pool(string, default"ball"). The Pool to take balls from.order(number[], default the 8-ball order). Ball numbers, apex first, then row by row from the top of the screen down.gap(number, default0). Extra space between neighbours, metres. 0 is a tight rack.rackKey(string, default"KeyR"). The key that racks again.
Events
Emits:
billiards.rack.racked,{ count }.
Listens to:
pool.ready, to rack the first time.keyboard.keydown, for R.billiards.rack.request, to rack again from a button or a game.
Dependencies
Pool. Where the balls come from.BilliardBall,MeshPrimitive. The balls.BilliardTable. Its bed gives the foot spot and the head spot.
Notes
- The rack only writes components. MeshPrimitive moves a pooled ball's mesh on the frame it comes out, and the table writes every mesh after that.
- With no table it racks on a default 2.54 × 1.27 bed centred on the origin.
- The cue ball leaves play and comes straight back when it is put on its spot, so its trail starts again there.



















