PinballPlayfield
The painted wood under the glass, drawn from code.
What it does
A real playfield is printed plywood under a hard clear coat, with translucent plastic inserts set into it and a lamp under each. This component paints that once, with a 2D canvas, and lays it on the table as a glossy ground at y = 0.
Everything is placed in table coordinates, [x, z], the same numbers the scene uses for the bumpers and ramps. So a ring you put at a bumper's x and z lands under that bumper, whatever size the texture comes out.
The coat is a physically based material with a low roughness. That is the part ScreenSpaceReflections needs: a shiny surface for the ball, the posts and the bumpers to show up in.
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 PinballPlayfield
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.
Hide the playfield box's mesh with "visible": false and keep its physics. Two surfaces at the same height flicker.
Props
width,depth(numbers) — the table's size. Match PinballTable.pixelsPerUnit(number, default48) — texture detail. 48 on a 16 × 78 table is 768 × 3744 pixels. Capped at 8192 on a side.topColor,bottomColor(RGB 0..1) — the base coat at the far end and at the player's end.stripeColor(RGB),stripes(number, default6) — neon pinstripes up the table.grain(0..1, default0.25) — flecks in the clear coat.seedkeeps them the same every load.inserts— what is painted on. Each has akind, anatof[x, z], and asizeandcolor:halo— a lit ring, for under a bumper or a saucer.sizeis its radius.lamp— a round insert, for a rollover lane.arrow— a chevron pointing at a shot.anglein radians; 0 points up the table.text— words painted flat.sizeis the letter height.band— a soft stripe across the whole table atz.sizeis how deep it is.image— a picture printed into the wood.srcis a URL or adata:URI,sizeis how wide it is, and its height follows the picture's shape.alpha(default0.85) lets the wood show through. The floor goes on at once and is painted again when the picture loads. A picture from another site must allow CORS, or it is left out.
roughness(default0.18),metallic(default0) — the clear coat.
Events
- Emits
pinballPlayfield.painted—{ entityId, width, height }in texture pixels, once the art is on. - Listens for
pinballPlayfield.repaint—{ entityId? }, paint again (after changinginserts).
Notes
- With no DOM (a headless test, a worker) it paints nothing and says nothing.
- The art is a JPEG data URL, so there is no file to download or host.























