workshop private

← all creations

Tangent

mechanics · created 2026-09-14

Pot the ball and stop the cue ball on a mark, with the two rules every pool player is handed — the tangent line and "thirty degrees" — turned back into the one fraction they both came from, which is 2/7, and which sets a ceiling of 33.75° that nothing you do with a cue can get past.

physicssimulationgame-feelcanvas

Potting is the easy half. Anyone can see where the object ball has to go: it leaves along the line joining the two centres at the moment they touch, always, and no spin, speed or cleverness changes that. The hard half is the other ball — the one you have to hit again next time — and the whole of pool is the question of where it ends up.

Players get handed two rules for that. The cue ball leaves on the tangent line, perpendicular to the object ball. And the cue ball deflects about thirty degrees. Both are true. They are also flatly contradictory, nobody explains when to switch, and they are the same equation with one parameter moved.

Everything here is 2/7

A solid sphere has I = (2/5)mR². That is the only physical fact in the piece; the rest is bookkeeping.

While the contact patch is slipping, friction acts on it, and the patch feels the friction twice — once through the centre of mass and once through the spin it induces:

u  = v + ω × (0,0,−R)          the velocity of the contact patch

du/dt = dv/dt + (dω/dt) × r_c
      = (1 + mR²/I) · dv/dt
      = (7/2) · dv/dt

So the patch’s velocity dies 7/2 times faster than the ball’s does, and by the time the skid is over the centre of mass has given up exactly (2/7)·u₀. Everything below is that sentence with different things substituted for u₀.

The collision, and the one number it leaves behind

Ball-on-ball is frictionless and equal-mass, so it takes the line-of-centres component and touches nothing else. The tangential velocity rides through untouched, and — the part that matters — so does the spin.

That is the whole reason the cue ball is predictable. Immediately after impact it has a small velocity and the full angular velocity it arrived with, so the patch is slipping hard, and the cloth spends the next few centimetres bending its path forward. Where it settles:

v_final = v_t·(5 + 2ρ)/7  +  v_n·(5ε + 2ρ)/7

with ρ the roll fraction at contact (0 = skidding, 1 = rolling, negative = draw) and ε = (1−e)/2 the sliver of normal velocity the impact hands back. Divide through by the tangential coefficient and the entire shot collapses to one number:

k = (5ε + 2ρ) / (5 + 2ρ)                        θ(φ) = 90° − φ − arctan(k·cot φ)
shotρk (perfectly elastic)
stun00 — the tangent line
half-skidding0.51/6
natural roll12/7
maximum follow1.251/3
maximum draw−1.25−2/3

k = 0 is the tangent line. The two rules were never two rules.

The ceiling, which is the good part

Differentiate θ(φ). It is stationary when tan²φ = k, and substituting that back collapses the arctan into the cut angle itself:

cut*  = arctan(√k)              θ_max = 90° − 2·arctan(√k)

The cut angle, the deflection, and the cut angle again tile a right angle. For a rolling cue ball, k = 2/7:

θ_max = 90° − 2·arctan(√(2/7)) = 33.749°,  at a cut of 28.126°

A rolling cue ball cannot deflect more than 33.75°, ever. Not at any speed, not at any cut, not with any cue. And at the miscue limit k is exactly 1/3, so √k = 1/√3, so the peak is exactly 30° at a cut of exactly 30°. Two suspiciously round numbers that nobody chose.

node scripts/measure.mjs integrates the table and checks all of it:

tip offsetρkpeak, closed format cutpeak, measured
0.10R0.250.090956.44°16.78°56.30°
0.20R0.500.166745.58°22.21°45.50°
0.30R0.750.230838.68°25.66°38.62°
0.40R1.002/733.75°28.13°33.75°
0.50R1.251/330.00°30.00°30.04°

So where does “thirty degrees” come from?

From the fact that θ(φ) near its peak is nearly flat. The cut angle sweeps 30° while the answer moves 3.75°:

cut15°20°25°28.13°35°40°45°55°70°
deflection28.16°31.87°33.50°33.75°32.80°31.20°29.05°23.69°14.06°

Which is why a rule of thumb exists at all, and exactly where it stops working:

cuterror of “30°”miss at 80 cm of cue-ball travel
−11.81°16.5 cm
12°−5.35°7.5 cm
17°−0.06°0.1 cm
28.13°+3.75°5.2 cm
43°−0.03°0.0 cm
60°−9.37°13.1 cm
70°−15.94°22.2 cm

Under a ball-width from 17° to 43°, and off the table by 70°. It is not a rule, it is a plateau with two cliffs, and the skill is knowing you have walked off one. The demo’s fan draws that directly: one shot line, the fullness of the hit sweeping 6° to 72°, every exit heading redrawn from a common origin and coloured by whether 30° was still true. Twelve of twenty-six, at natural roll.

The tangent line is exact, and it expires

Set ρ = 0 and θ = 90° − φ: the cue ball leaves perpendicular to the object ball. Twelve measured shots, four cut angles, five-fold speed range:

cut1.0 m/s2.5 m/s5.0 m/s
15°88.74°89.83°89.92°
30°89.42°89.92°89.96°
45°89.66°89.96°89.98°
60°89.81°89.97°89.99°

Ninety degrees, to a decimal place, across a five-fold speed range and a 45° spread of cut angle. No speed term, no cut term, no mass term. The residual — worst at 15° and 1 m/s, where it reaches 1.3° — is not the rule failing: it is ρ, which has already climbed to 0.015 in the 2 mm the ball is given before contact, and which is the subject of the next section. Real balls also give back about 2% of the normal component, and that error goes as cot φ — 1° on a thick cut, 7° on a thin one, which is backwards from where anyone would guess.

And then there is the thing nobody mentions. ρ is not something you set with the cue. It is something the cloth sets on the way there. The same dead-centre hit, from further away each time:

distance to the object ballρ at impactseparation
0.01 m0.01389.50°
0.10 m0.13484.95°
0.30 m0.47874.47°
0.60 m1.00063.67°
1.60 m1.00063.67°

A centre-ball hit at 1.5 m/s is fully rolling after 28 cm. So a “stun shot” across the table is not a stun shot — it is a roll shot you have mislabelled, and the tangent line you drew for it is off by 26°. The demo makes this its own screenshot: the identical shot struck at 2R/5 and struck dead centre, over 85 cm of cloth, deflect 32.57° and 32.57°. Identical to two decimals. The cue never got a vote.

Draw goes the other way — ρ negative, k negative, the cue ball comes back through the tangent line — and the same formula covers it without a special case:

tipρ20° cut40° cut
−0.20R−0.50104.38°66.53°
−0.35R−0.87125.89°82.63°
−0.50R−1.25139.97°99.96°

Three beliefs, one drill

The game layer is thin on purpose: pot the ball, stop the cue ball on a mark. Nothing in it knows about any of the above. So the measure script runs 640 generated layouts — each one built from a cut angle rather than found by rejection sampling, each confirmed by playing it first — and sends three autopilots at them. They pot identically and share one distance model. The only thing under test is what each believes about which way the cue ball leaves.

pilotpottedwithin 12 cmwithin 5 cmmean miss
“it follows the tangent line”70.8%57.8%3.8%12.1 cm
“thirty degrees”100.0%100.0%100.0%2.5 cm
the closed form100.0%100.0%100.0%2.6 cm

One constant, carried in the head with no trigonometry, is worth as much as the exact model — inside the plateau. That is the honest version of the folklore: not that 30° is right, but that 30° is right enough over a wide enough band that the arithmetic buys you nothing, and the thing actually worth knowing is the band’s edges.

The tangent-line pilot pots only 71% because its speed model is fed by its direction model, and a shot aimed to stop somewhere unreachable comes up short. That is a real consequence of a wrong belief rather than a harness artefact, but it does mean its 12 cm is flattered — it is partly failing earlier.

What is physics here and what isn’t

The first version of stepBall chattered across the slip/roll boundary and put a few degrees of noise into every deflection. It now lands on u = 0 exactly — if a step would carry the patch velocity through zero, it takes the (2/7)u out of the centre of mass in one go and switches to rolling. That is why the measured column matches the closed form to 0.00° instead of 0.4°.

Reuse

src/tangent.mjs is framework-free with no canvas in it.

The demo is demo/index.html with its own copy of the module (ADR-0002): pointer or arrow keys to aim, hold to charge and release to shoot, ↑/↓ for tip height against a drawn miscue limit, F for the fan. Every aim line it draws is clipped at the first cushion, because the prediction has no rail in it and drawing it through one would be claiming something the line does not know.

node scripts/screenshot-demo.mjs regenerates the thumb and media and is the smoke test: it fires a real pointer-drag, checks the demo’s aim-time prediction against its own simulation to 2.5°, and asserts that the same cut struck dead centre from 8 cm separates more than 15° wider than struck rolling — it is 24° in practice, 85.1° against 60.7°. That last one is written as a comparison rather than ”≈ 90°” on purpose — the first version asserted 90° from the normal shooting distance and failed, correctly, because over 85 cm of cloth there is no such thing as a stun shot.