SHIPPEDgame

PuttX

Hard 3D mini golf for players around 12: ten worlds, 549 holes with solver-proven pars, a real putter stroke. One HTML file, no reading, works offline.

CREATED OCT 11, 2026 · UPDATED OCT 15, 2026

PROBLEM

Mobile mini golf is either a tap-to-power slot machine or a free-to-play funnel. Neither has a stroke you can get better at, and neither tells a player why the putt missed.

It started the same morning as a gentle 27-hole sequel to Vroom for a 3-to-5-year-old, and was rebuilt before the day was out as v2: harder, 3D, for players around 12.

HYPOTHESIS

A swing gesture with real mishits (decelerate and it comes up short, jab and it runs long, drift and you push it) is enough skill for a 12-year-old to chase, provided the course is provably fair. Fair means a machine proves every par, so "too hard" is a measurement rather than an argument.

ARCHITECTURE

Sources assemble into one shipped index.html: a shell, the game script, the pro shop, one sim file and one look file per course, and three.js r170 inlined from node_modules. A build check fails when the shipped file is stale.

The physics is hand-rolled and deterministic at a fixed 240 Hz, inside a sim region that is DOM-free and three-free and runs straight from source in Node. Rolling at 5/7 g sin(theta) on slopes, a skid phase before true roll, crest launches and landing bounces, five surfaces, movers, tubes, and a cup whose capture depends on speed and line.

Holes are data. A beam-search solver proves each par and writes the solution into the hole; a second bot with human-sized aim and pace error measures how hard the hole really plays. The suite refuses any hole where more than 4% of tee shots ace, or where any prop overlaps another.

STACK

JavaScriptthree.jsWeb AudioPlaywrightESLint

RESULT

Live on GitHub Pages. Ten worlds of three courses, 18 holes each, plus a nine-hole bonus course of deliberately unhinged stunt runs. Three save profiles, a pro shop of putters and balls, a worlds map, and no fail state: after double par the ball rolls itself in. 121 commits across five days, 65 of them on the first.

MEASURED

metricvaluebaseline
holes549 · ten worlds of three 18-hole courses, plus a bonus nine—
pars proven by solverevery hole · solutions stored in the hole data—
ace ceiling4 % · of tee shots, asserted per hole—
physics step240 Hz · fixed, deterministic—
minimum touch target64 px · rendered at 1024x768—
words on screen0 · numerals and symbols; the logo is the one exception—

LEARNINGS

  • A solver is the only honest difficulty setting. Loosening the physics left a batch of stored solutions stale, and re-solving them is how the change announced itself.
  • v1 and v2 shipped on the same day. Dropping the preschool version cost one morning; the physics carried straight over.
  • Keeping the sim DOM-free and clock-free meant Node could replay any hole exactly. That one constraint is what made felt possible two weeks later.

PROVENANCE

Built 2026-10-11 to 2026-10-15 in Claude Code. The pars, difficulty ratings and solutions come from scripts/solve.cjs, not from hand tuning; the course packs were reworked once from ten separate world briefs.

TAGS

game3dphysicsdeterministicsolverofflinepwa