The Physics of CueVR

The published work on cue-sports physics, and how this engine implements it.

This page has two halves and a join. Part I is a review of the literature — written to teach the physics rather than to name papers, so the slip decay, the 5/7 and 2/7 factors, the 90-degree rule and the throw cap are derived here rather than asserted. Part II describes what this engine actually does, with the model, the equations and the constants, and cites the source file and line for every non-trivial claim. Between them is a list of everything in the review the engine has not taken up.

Where a source could not be verified, the review says so rather than quietly citing it. Three attributions in common circulation did not survive checking and are corrected in place.

← back to the player's guide

Part I — The published work

What is known about how billiard balls behave, and how simulators have modelled it.

Part I contents

A literature review for the background and related-work sections of a paper on a VR cue-sports engine

Compiled September 2026.


0. Scope, method, and how to read the citations

This review covers the physics of billiards, pool and snooker and the numerical methods used to simulate it, with a short section on the VR-specific problems of tracking a hand-held implement. It is written to be read and learned from: the important relations are derived rather than merely named, so that a reader coming from graphics or HCI rather than from contact mechanics can follow the argument.

Cue sports occupy an unusual position in the sports-physics literature. The core problem — rigid spheres of equal mass, rolling and sliding on a nearly flat, nearly uniform surface, colliding nearly elastically — is clean enough that closed-form answers exist for most of it, which is why it has been a physics-teaching staple since 1835. But the field is small, and a great deal of the usable knowledge lives outside the peer-reviewed literature, in books by enthusiast-engineers, in a long-running instructional magazine column, and in the documentation of open-source simulators. Any honest review must say which is which, so the source type is stated for every reference:

Where a numerical value is quoted, its source and the spread between sources are given. Where the literature is genuinely thin, this is stated rather than papered over. Sections 3 (cushions), 4 (pockets) and 6 (VR implements) contain the largest gaps, and those gaps are flagged explicitly in §8.


1. Classical foundations of billiard-ball dynamics

1.1 Coriolis (1835): what he actually established

Gaspard-Gustave de Coriolis published Théorie mathématique des effets du jeu de billard in Paris in 1835 [1]. It is a 208-page monograph, not a paper, and its structure is worth setting out because the standard secondary description of it ("the first mathematical treatment of billiards") badly undersells its scope. The chapter list, taken from the scanned first edition held by the Bibliothèque nationale de France [1], is:

Chapter p.
— Exposé des principales conséquences de la théorie... (a non-mathematical summary of results and the geometric constructions that give the ball motions) 1
I Du mouvement d'une bille sur un plan horizontal en ayant égard aux frottements — motion of a ball on a horizontal plane, accounting for friction 51
II De l'effet du coup de queue horizontal — the effect of a level cue stroke 78
III Du choc de deux billes et du carambolage, en négligeant le frottement très-petit qui a lieu entre les billes pendant le choc — two-ball collision and the carom, neglecting the small inter-ball friction 101
IV Des effets d'un deuxième choc entre deux billes, après un premier choc — the effects of a second ball-ball collision 112
V Du choc de deux billes, en ayant égard au frottement entre les billes pendant le choc, au défaut d'élasticité, et à l'inégalité des masses — two-ball collision including inter-ball friction, imperfect elasticity, and unequal masses 119
VI Du choc contre la bande, soit directement, soit après un autre choc — impact against the cushion, direct or following another impact 135
VII Cas particulier où il faut modifier les formules... relatives à l'effet du frottement pendant le choc — the special case requiring modified friction formulae 143
VIII De l'effet du coup de queue incliné — the effect of an elevated (inclined) cue stroke 146

So Coriolis did not merely write down the frictionless two-ball collision. He treated ball–cloth friction, the tip impulse, the frictional and inelastic ball–ball collision with unequal masses, the cushion impact, and the massé shot — that is, the whole problem, in an order a modern simulator author would recognise. Chapters III and V are structured exactly as a modern paper would be: solve the idealised case first, then add friction and restitution as corrections.

Four results from the book are still routinely quoted, and the clearest modern restatement of them is Alciatore's survey article [2] (a practitioner-authored technical article, self-published on the author's site after an AJP submission):

  1. The post-impact cue-ball path under top or bottom spin is a parabola. (Derived in §1.6 below.)
  2. The tip offset for maximum safe sidespin is half a ball radius, i.e. the contact point should not exceed R/2 from the vertical centre line, beyond which the tip slides and the shot miscues.
  3. The massé aiming construction ("BAR" in Alciatore's naming): the final direction of the cue ball is parallel to the line from the ball's original resting point to the aiming point on the cloth.
  4. For a cue ball in natural roll, the maximum possible deflection angle after impact with an object ball is 33.7°, occurring at a cut angle of 28.1°. This is the origin of what English-language instruction calls the "30° rule".

Coriolis' book was not widely read in the Anglophone world because it was never translated until David Nadler produced an English edition in 2005 [3] [B]. That translation is the reason the 1835 results re-entered the modern literature; both Mathavan et al. [4,5] and Alciatore [2] cite Nadler rather than the French original.

Why it is still cited. Three reasons. First, priority: almost every relation in §§1–2 below appears in the 1835 book. Second, completeness: Coriolis treated the frictional collision and the elevated cue, problems that most twentieth-century papers dropped in favour of the frictionless case. Third, and most practically, his geometric constructions are still the fastest route to a qualitative answer, and the modern papers explicitly benchmark against his conclusions (Mathavan et al. [4] compare their measured cushion restitution to Coriolis' value; Alciatore [2] provides a "modern proof for the numbers in Coriolis' 4th conclusion").

1.2 The state of a ball on cloth, and the contact-point slip

A ball on the table has thirteen numbers of interest but only six degrees of freedom: centre-of-mass position r and velocity v, and orientation and angular velocity ω. Because the ball is a homogeneous sphere its inertia tensor is isotropic,

I=25mR2 1,

which is derived in full in Shepard [6] (§1, Problem 1.3) [C]. Isotropy is the single most important structural fact in billiard physics: Iω is always parallel to ω, so angular momentum and angular velocity never separate, there is no precession, and every rotational equation reduces to a scalar multiple. A simulator can carry ω as a plain 3-vector and never needs an inertia tensor rotation.

The quantity that governs everything on the cloth is the contact-point slip velocity. With z^ up and the contact point at −Rz^ relative to the centre, the velocity of the material point of the ball momentarily at the contact is

u  =  v+ω×(−Rz^)  =  v+R (z^×ω).

If u=0 the ball rolls; otherwise it slides. The rolling condition written out for straight-line motion is the familiar v=Rω — a ball moving at v whose surface is turning at Rω lays its surface down on the cloth without scuffing. Note that u is unaffected by the component of ω along z^: sidespin about the vertical axis does not appear in the slip velocity at all, because the contact is (idealised as) a point on the spin axis. This is why vertical-axis spin has to be treated as a separate third regime (§1.5), and why the point-contact idealisation eventually has to be broken.

1.3 Sliding to rolling: where 5/7 and 2/7 come from

Take a sliding ball. Coulomb friction acts at the contact, opposing the slip:

F=−μsmg u^,u^=u/∣u∣.

Linear and angular accelerations follow:

v˙=−μsg u^,ω˙=I−1[(−Rz^)×F]=5μsg2R (z^×u^).

Differentiate the slip:

u˙=v˙+R(z^×ω˙)=−μsg u^−52μsg u^=−72 μsg u^.

Two consequences, and they are the reason billiards is analytically tractable at all:

(a) The slip direction is constant during a sliding phase. u˙ is antiparallel to u^, so u^ never rotates; only ∣u∣ shrinks, linearly, at rate 72μsg. The friction force is therefore constant in both magnitude and direction for the whole slide. Constant acceleration plus an initial velocity gives a parabola — which is Coriolis' first conclusion, and also the reason that the swerve of a massé shot is parabolic. Alciatore [2] notes that infrared high-speed video of the frictional heat trace on the cloth shows the parabola directly.

(b) The slide has a closed-form duration and length. Sliding ends at

tslide=2 ∣u0∣7 μsg.

For collinear motion (topspin/backspin only, no sidespin) the same result can be reached by eliminating the impulse between the linear and angular equations, as Shepard does [6, §2]:

IR(ω−ω0)=−m(v−v0)  ⟹  v=v0−25R(ω−ω0),

a relation independent of μs and of m. Imposing the rolling condition v=Rω gives the natural-roll speed

  vroll=57 v0+27 R ω0  

This is where the 5/7 and 2/7 come from. Special cases worth committing to memory:

The 7R/5 height. A horizontal cue impulse J delivered at height h above the cloth produces v0=J/m and, by moment about the centre, ω0=J(h−R)/I=5J(h−R)/(2mR2). Demanding immediate natural roll, Rω0=v0, gives

  h=75R=1.4R=0.7D  

This is the ball's centre of percussion for a horizontal impulse. It appears again, and importantly, in the cushion discussion (§3.2). Salazar and Sánchez-Lavega [7] [P] give the general treatment of a ball struck by a tapering rod, and this is the result Mathavan et al. cite for it [4].

1.4 Rolling resistance

A rolling ball still decelerates, because the cloth is deformable. The ball sinks into the nap; the contact patch is not a point but a small region, and the pressure distribution over it is fore-aft asymmetric because the cloth fibres relax more slowly than they compress. The resultant normal reaction S therefore acts ahead of the contact centre and tilted from the vertical by a small angle β, giving a retarding horizontal component Ssin⁡β and a torque opposing ω. Mathavan et al. [4] give this picture explicitly, citing the rolling-friction treatments of Hierrezuelo and Carnero [8] [P] and Doménech, Doménech and Cebrián [9] [P].

The engineering consequence is that rolling resistance is well modelled as a constant deceleration μrg that does not depend on speed [4, citing 8]. Shepard [6] parameterises the same thing as table speed, defined as 1/μr, measured by rolling a ball distance d in time t to a stop, μr=2d/(gt2). He gives: very slow table 50–70, normal 80–100, fast pool table above 120, fast carom table above 150 — i.e. μr from about 0.020 down to below 0.007.

1.5 Spin about the vertical axis

Because vertical-axis spin does not enter the slip velocity of a point contact, a point-contact model predicts that sidespin never decays — which is plainly false. The resolution is that the contact is a patch of radius a, and the tangential tractions over the patch produce a drilling (spinning) friction torque. For a circular patch of radius a under uniform pressure,

Mz=−23 μ mg a  ⟹  ω˙z=−MzI=−53 μgaR2,

a constant angular deceleration. Simulators generally absorb a into a phenomenological dimensionless "spinning friction" coefficient μsp, writing ω˙z=−52μspg/R; comparison of the two forms gives μsp=23μa/R. The μsp form is the one used in the open-source pooltool simulator, whose physics documentation [10] [C/S] is unusually explicit about the model and states plainly that μsp is a phenomenological parameter standing in for the finite contact area.

Alciatore's compiled property table [11] [C] gives the empirical answer directly as a ball–cloth spin deceleration rate of 5–15 rad s⁻², which is the most directly usable number for an implementer.

Mathavan et al. [4] add an interesting empirical observation on this point: they never observed a ball continuing to spin about the vertical axis after its linear motion had stopped, and conclude that a billiard ball on cloth exhibits partly disk-like coupling between translation and rotation, citing Voyenli and Eriksen's analysis of the ice-hockey puck [12] [P]. Whether translational and spin motion genuinely terminate simultaneously for a billiard ball, as they provably do for a uniform disk, is not settled — Mathavan et al. offer it as an observation, not a proof.

1.6 The elevated cue: squirt, swerve and the massé

Three distinct effects displace the cue ball from the line the player aimed along, and they are routinely confused. Alciatore [2] separates them cleanly:

Squirt (cue-ball deflection). When the tip strikes off the vertical centre line, the cue ball leaves not along the cue's axis but deflected away from the side the tip struck. The mechanism is not friction: it is that the end of the cue shaft has mass, and as the ball rotates under the tip during the ~1.5 ms of contact, the shaft end must be pushed sideways; the reaction pushes the ball the other way. The governing quantity is the cue's effective endmass me — how much of the shaft's mass is brought into play before the transverse elastic wave has travelled away from the tip. Shepard derives the relation [13] [C]; Cross measured it experimentally with the cue ball suspended as a pendulum bob [14] [P]. Alciatore's endmass experiments [2] found that adding mass to the shaft beyond about 18 cm from the tip had no effect on squirt, which is a direct measurement of the wave-transit length. Squirt angle is very close to linear in tip offset. Kim [15] [P] gives an independent theoretical treatment of the cue–ball collision and derives the squirt angle for an oblique strike.

Cross has continued this line, and the later papers matter for a VR engine because they concern where a stroke's energy actually goes. Cross [14] measured that an unchalked tip slides across the ball, producing a large squirt angle, whereas a chalked tip grips it, producing a smaller one. Cross [133] [P] then found that a large fraction of the energy loss in a stroke occurs in the tip rather than in the cue, and — significantly for anyone modelling a hand-held implement — that the player's hand alters both the cue's effective mass and the coefficient of restitution. Cross [134] [P] relates outgoing speed and spin to the impact point above or below centre and compares the measurements with a simple impact model. Shimamura et al. [135] [P] examine how the cue's material properties affect the resulting ball trajectory.

Swerve. With the cue elevated, the tip imparts a spin component about the aiming-line axis ("massé spin"). This spin puts a slip velocity at the contact perpendicular to the direction of travel, so the constant sliding-friction force of §1.3 has a lateral component, and the ball follows a parabola — curving back toward the aim line, or past it, depending on the sign. Swerve is a cloth effect and grows with the time and distance available before the object ball; squirt is a tip effect and happens instantly. A player compensating for one is not compensating for the other.

Massé. With extreme elevation the same mechanism is pushed to its limit and the cue ball describes a pronounced arc. Coriolis' Chapter VIII treats this, and his aiming construction (§1.1, result 3) is a geometric restatement of the parabola. Walker's Scientific American article [16] [C] is the standard popular exposition of follow, draw and massé and is cited as such by both Mathavan et al. [4] and Alciatore [2].

An important and often-missed point from Mathavan et al. [17] is that the massé mechanism also operates after every ball–ball collision: friction at the ball–ball contact, acting on a cue ball that has topspin, imparts a spin component about the cue ball's own forward velocity axis, producing exactly a small massé and hence a curved path. Their 2014 paper adds this correction to the post-collision trajectory prediction.

1.7 Measured coefficients, and the spread between sources

This is where an implementer needs to be careful, because the published numbers disagree by factors of two, and some of the disagreement is real (different cloth, different balls, snooker vs. pool) while some of it is measurement error in the older sources.

Quantity Value Source Type Notes
Ball diameter, pool 2.25 in = 57.15 mm (+0.005 in) WPA equipment spec [18] [C] standards body
Ball mass, pool 5.5–6 oz = 156–170 g WPA [18]; Shepard [6] [C]
Ball radius/mass, snooker R = 26.25 mm, M = 0.1406 kg Mathavan et al. [5,17] [P] the values used in their simulations
Ball diameter, snooker 52.5 ± 0.05 mm WPBSA rulebook [49] [C] standards body Shepard [6] gives 2⅛ or 2 1/16 in for older sets; Mathavan et al. measured 52.4 mm [4]
Ball weight tolerance, snooker ≤3 g spread within a set WPBSA [49] [C] no absolute mass is specified
Ball diameter, carom 2 27/64, 2⅜ or 2 7/16 in; 7–7.5 oz Shepard [6] [C] carom balls are heavier
Moment of inertia 25mR2 exact for a homogeneous sphere —
Ball–cloth sliding friction μs 0.178–0.245 (snooker, measured) Mathavan et al. [4] [P] deceleration 1.75–2.40 m s⁻²; they use 0.21 as the average [5,17]
0.2 (pool, computed) Marlow [19] [B]
0.14 rising to 0.21 with speed Witters & Duymelinck [20] [P] stroboscopic photography; Mathavan et al. could not reproduce this speed dependence [4]
0.15–0.4, typical 0.2 Alciatore [11] [C] compiled range
Ball–cloth rolling resistance μr 0.0127–0.0129 (snooker, measured) Mathavan et al. [4] [P] deceleration 0.124–0.126 m s⁻²
0.011–0.024, mean 0.016 (pool) Marlow [19] [B] Mathavan et al. explicitly criticise this >100% spread as a metre-stick-and-stopwatch artefact [4]
0.005–0.015 Alciatore [11] [C]
~0.007–0.020 (as 1/table speed) Shepard [6] [C]
Ball–cloth spin decay 5–15 rad s⁻² Alciatore [11] [C]
Ball–ball friction μbb 0.05 (best fit to high-speed data) Mathavan et al. [17] [P] fitted over 0–0.2 in 0.01 steps
0.06 (polished); up to 0.2 with chalk Marlow [19] [B]
μbb=9.951×10−3+0.108 e−1.088s Marlow [19] [B] speed-dependent; s = slip speed. Mathavan et al. judge the experiment behind it unreliable [17]; Alciatore uses the same functional form fitted to his own and Marlow's data [2]
0.03–0.08 Alciatore [11] [C]
Ball–ball restitution e 0.89 (best fit) Mathavan et al. [17] [P]
>0.92 Marlow [19] [B]
~0.93 Alciatore [2] [C] quoted as the reason the "90° rule" is really an 85° rule
0.92–0.98 Alciatore [11] [C]
Ball–cushion restitution 0.98 (true, from the impulse model) Mathavan et al. [5] [P] this is the energetic COR inside the 3D model
0.818 (effective, ball rolling, normal incidence, 0.28–3.5 m/s) Mathavan et al. [4] [P] lumps in friction and 3-D effects; not the same quantity as 0.98
0.910 (low-speed limit, rigid cushion) Mathavan et al. [4] [P] slope of the rebound curve at low speed
0.55 (pool) Marlow [19] [B] Mathavan et al. argue this measures the speed after the post-impact slide, not the impulse [4]
0.6–0.9 Alciatore [11] [C]
Ball–cushion friction μw 0.14 Mathavan et al. [5] [P]
Ball–table restitution 0.5–0.7 Alciatore [11] [C] for a ball dropped/hopping
Tip–ball friction ~0.6 (0.58 at 0.5R, 0.66 at 0.55R offset) Alciatore [2,11] [C] sets the miscue limit
Tip–ball restitution 0.71–0.75 (leather); 0.81–0.87 (phenolic) Alciatore [11] [C]

Reading this table. The single most useful observation is that the two best-instrumented studies — Mathavan et al.'s high-speed vision work [4] and Alciatore's high-speed video and robot work [2] — agree with each other far better than either agrees with the older stopwatch-era numbers. Where Marlow [19] and the modern measurements disagree (rolling resistance, cushion restitution), there is a specific, stated methodological reason to prefer the modern number. Marlow's book remains valuable for the forms of the relations, especially the exponential speed-dependence of μbb, which Alciatore independently re-fitted and found to describe his data well [2].

The second observation is that "coefficient of restitution" for a cushion is three different quantities depending on what you measure (§3.4), and quoting 0.98, 0.91, 0.82 and 0.55 as though they were competing estimates of one number is a mistake that appears repeatedly in secondary sources.


2. Ball–ball impact

2.1 The 90° rule, and why it is really about 85°

Two equal-mass spheres, frictionless and perfectly elastic, one initially at rest. Let n^ be the unit vector along the line of centres at contact ("impact line") and t^ perpendicular to it in the table plane ("tangent line"). A frictionless impulse can only act along n^, so the cue ball's tangential component is untouched:

vc,t′=vc,t,vo,t′=0.

Along n^, momentum and energy conservation for equal masses give the classic one-dimensional exchange: the balls swap normal velocities, vc,n′=0, vo,n′=vc,n. Hence the cue ball leaves purely along t^ and the object ball purely along n^: the outgoing paths are perpendicular, whatever the cut angle. If ϕ is the cut angle (between the cue ball's incoming line and the object ball's outgoing line),

vo=v0cos⁡ϕ,vc=v0sin⁡ϕ.

Two immediate corollaries. At ϕ=0 the cue ball stops dead (the stop shot). And the ghost-ball aiming construction follows directly: to send the object ball along a chosen line, place an imaginary cue ball tangent to the object ball on the far side of that line, and aim at its centre. Alciatore [2] gives the terminology and the construction.

The 90° rule is exact only for (i) equal masses, (ii) a perfectly elastic collision, and (iii) a cue ball with no vertical-plane spin at contact — i.e. a stun shot. Condition (ii) fails: with e≈0.93 the cue ball retains a little impact-line momentum, so the separation angle is nearer 85° [2, TP A.5]. Condition (i) fails on coin-operated tables with an oversized cue ball, and fails slightly everywhere because the cue ball wears fastest [2]. Condition (iii) fails on most shots, which is the subject of §2.3.

2.2 Cut-angle geometry

The standard parameterisation, used by Wallace and Schroeder [21] [P] and repeated by Mathavan et al. [4], is the fractional impact parameter

β=b/D=sin⁡ϕ,

where D is the ball diameter and b is the perpendicular offset of the ball centres from the incoming velocity line. A half-ball hit (β=0.5) corresponds to ϕ=30°; a quarter-ball hit to ϕ≈14.5°; a three-quarter-ball hit to ϕ≈48.6°.

2.3 The rolling cue ball, and the 30° rule

Most shots reach the object ball with the cue ball in natural roll, so condition (iii) fails. What happens is a two-stage process, and the second stage is on the cloth, not in the collision:

  1. The collision strips the cue ball's velocity component along n^ but leaves its angular velocity essentially unchanged (the friction impulse between balls is small, and angular momentum about the ball's own centre is nearly conserved [2, TP A.6]).
  2. The cue ball therefore emerges along the tangent line with far too much spin for its new speed — the overspin case of §1.3. Sliding friction then accelerates and turns it until natural roll is re-established, after which it travels straight.

The net deflection θc of the cue ball from its original aiming line, after the post-impact slide has finished, is (Wallace and Schroeder [21], quoted in this form by Mathavan et al. [4] eq. 2 and by Alciatore [2] eq. 1):

θc=tan⁡−1 ⁣[sin⁡ϕ cos⁡ϕsin⁡2ϕ+25]

with the corresponding post-slide speeds

Vo=57 Vcos⁡ϕ,θo=ϕ,Vc=57V95sin⁡2ϕ+425.

The 25 in the denominator is the ball's dimensionless moment of inertia and the 57 prefactors are the natural-roll factor of §1.3 — this is a cloth result wearing a collision's clothing.

Recovering Coriolis' 33.7°. It is worth doing this maximisation, because it shows that Coriolis' fourth conclusion and the Wallace–Schroeder formula are the same result. Write k=2/5 and use the double-angle identities:

tan⁡θc=sin⁡ϕcos⁡ϕsin⁡2ϕ+k=12sin⁡2ϕ12(1−cos⁡2ϕ)+k=sin⁡2ϕ(1+2k)−cos⁡2ϕ.

Setting x=2ϕ and differentiating, the numerator of d(tan⁡θc)/dx is cos⁡x (1+2k)−1, so the maximum is at

cos⁡2ϕ=11+2k=11.8  ⟹  ϕ=28.13°,θcmax⁡=33.75°.

These are exactly Coriolis' numbers. (I verified this numerically as well as analytically.) It is a pleasing check on 190 years of transcription.

The practically important part is not the peak value but that θc is flat near its maximum: it stays close to 30° for ball-hit fractions from ¼ to ¾ [2]. That flatness is the entire content of the "30° rule" and the reason it survives as a practitioner heuristic — a player can be substantially wrong about the cut angle and still predict the cue ball's line.

Onoda [22] [P] published a comment on Wallace and Schroeder in AJP the following year, and both Alciatore [2] and Mathavan et al. [4] cite Wallace-and-Schroeder-plus-Onoda together as the supporting analysis. Wallace and Schroeder's own experimental validation was incomplete: their tracking method recorded positions but not times, so they could not check the velocity relations. Mathavan et al. [4] supplied that check with high-speed video, finding agreement within about 10% on post-collision speeds (their Table I), with the largest disagreement for θo at large impact parameters.

2.4 Throw: why object balls do not travel along the line of centres

Throw is the deviation of the object ball from the pure impact-line direction, and it is caused by tangential friction at the ball–ball contact. There are two sources, and Alciatore's naming for them [2] is now standard:

Alciatore's model [2, TP A.14] gives the throw angle as

θthrow=tan⁡−1 ⁣[min⁡ ⁣(am+bme−cm(vsin⁡ϕ−Rωz)2+(Rωxcos⁡ϕ)2  (vsin⁡ϕ−Rωz)2+(Rωxcos⁡ϕ)2vcos⁡ϕ,  17(vsin⁡ϕ−Rωz)vcos⁡ϕ)]

Two features of this expression are worth understanding because they explain the observed behaviour and because a simulator that omits either will be visibly wrong:

The exponential friction model. am,bm,cm parameterise a μbb that decreases with relative surface speed, following Marlow's form [19] refitted by Alciatore. This is why fast shots throw less than slow ones at large cut angles.

The 1/7 cap. The min enforces that the relative sliding at the contact cannot reverse during the impact. Once the surfaces stop slipping relative to each other, friction can do no more work, so there is a hard ceiling on the total tangential impulse. Deriving it: the tangential impulse Pt changes the relative surface velocity by contributions from both balls' linear motion (2Pt/m) and both balls' spin about the contact (2⋅PtR2/I=5Pt/m), so Δut=7Pt/m; setting Δut=ut,0 gives the maximum useful impulse and hence the 1/7 factor. Alciatore notes explicitly that prior treatments in the literature — he names Shepard's chapter 4 [6] — omitted this no-slip-reverse constraint.

The consequences, from Alciatore's Figure 20 [2], are: - at small cut angles throw is independent of speed (the 1/7 cap binds, so μbb drops out entirely) and grows with cut angle; - at larger cut angles throw is strongly speed-dependent (slow shots throw much more); - the maximum throw occurs near a half-ball hit, ϕ≈30°.

Experimental confirmation comes from Jewett's measurements in Billiards Digest [23] [C] — Alciatore reproduces Jewett's data as his Figure 21 — and from Alciatore's own two-part throw study [24,25] [C]. This is an area where the practitioner literature carries the experimental weight; there is no refereed paper presenting a comparable throw dataset.

2.5 The modern impulse-based collision models

Four bodies of work go beyond the algebraic treatments above and integrate the collision as a process:

Mathavan, Jackson and Parkin (2014) [17] [P] derive three sets of twelve differential equations for the two-ball collision on a rough surface, using the normal impulse PI rather than time as the independent variable — the standard device from Stronge's Impact Mechanics [26] [B] — and integrate numerically, tracking whether each ball is rolling, sliding or airborne at each of the three contacts (ball–ball, and each ball with the cloth). They fit μbb=0.05, e=0.89 against their own high-speed data, and report that their method roughly halves the error in post-collision speed and doubles the accuracy of predicted travel direction relative to the Wallace–Schroeder algebraic prediction. They also derive the post-impact parabolic path arising from the induced frontal-axis spin (§1.6).

Doménech has a long series on non-smooth collision modelling, culminating in "Non-smooth modelling of billiard- and superbilliard-ball collisions", International Journal of Mechanical Sciences 50(4):752–763, 2008 [27] [P], which treats the collision as a two-step discontinuous process (ball–ball interaction, then ball–surface interaction) for a cue ball with arbitrary pivot and sidespin. He has continued the theme with an "independent friction–restitution" framework, e.g. Mechanics Research Communications, 2023 [28] [P] — I confirmed this article exists and is by A. Doménech-Carbó, but was unable to retrieve the full record, so the volume and page numbers should be checked before citing.

Peskin (2020) [29] [R] gives a compact, self-contained centre-of-mass treatment of the general 3-D collision of two identical spinning balls under Coulomb friction. His framing is the most directly implementable of the set: because the balls are identical and the frame is the centre of mass, ball B's state is always the negation of ball A's, halving the problem. He shows that when sliding friction is the only dissipative mechanism the outgoing state is determined unambiguously by the incoming state, and that adding compression-phase dissipation introduces a one-parameter family of solutions. That last point is the honest statement of why "coefficient of restitution" is not a single well-defined number for a frictional collision — a point simulator authors often discover the hard way.

Kim (2024) [30] [P] analyses the collision of two spinning balls including all three deviations from the ideal — inelasticity, ball–ball friction and ball–table friction — and concludes that friction "significantly influences the post-collision motions". Its companion [15] does the same for the cue–ball impact. Both are single-authored and both, despite circulating widely as arXiv preprints, are published in New Physics: Sae Mulli.

Note the pattern: every one of these treats the collision by integrating over the normal impulse with the contact state (stick/slip) re-evaluated at each step. That is the correct structure for a high-fidelity ball–ball model, and it is not what most game physics engines do (§5).


3. Ball–cushion impact

This is the hardest part of billiard physics and the part where a simulator most obviously succeeds or fails, because banking is where players' expectations are sharpest.

3.1 Why mirror reflection is wrong

The naive model reflects the velocity about the cushion normal and scales the normal component by a restitution coefficient: outgoing eeV0sin⁡α normal, V0cos⁡α tangential. Mathavan et al. [5] call this "current theory" and list what it omits. Three things are wrong with it.

(a) The contact point is above the ball's equator. The cushion profile is cut so that the ball touches it above the horizontal great circle. The nominal reason is to stop the ball leaping into the air on rebound, and the geometry is unavoidable: the cushion has to be high enough to keep the ball on the table. The consequence is that the contact normal is tilted downward by an angle θ from horizontal, with

sin⁡θ=h−RR,

so the impulse has a vertical component and produces a torque about a horizontal axis — the impact necessarily changes the ball's topspin/backspin state and presses it into the cloth. Mathavan et al. take h=7R/5 and hence sin⁡θ=2/5 [5].

(b) There are three simultaneous contacts, not one. During the impact the ball is in contact with the cushion and with the cloth. Mathavan et al. [5] carry both: friction at the cushion (coefficient μw) and friction at the table (coefficient μs), with the table's normal reaction itself a function of the cushion impulse. This coupling is why the ball–cushion problem is genuinely three-dimensional even for a shot struck flat.

(c) The slip direction at the cushion is not constant. Unlike the cloth case of §1.3, where u^ is provably fixed, the slip direction at the cushion rotates during the impact. Mathavan et al. plot the slip–impulse curves and state directly: "the assumption of unidirectional slip cannot be true" [5, Fig. 12]. Any closed-form cushion model that assumes a fixed friction direction — including Marlow's [19], which they criticise on exactly this ground — is approximating.

3.2 Cushion nose height: 7R/5 versus 0.635D

This deserves its own subsection because the two numbers in circulation are not the same and the difference matters.

Mathavan et al. [5] state "In both snooker and pool h=7R/5", and in their 2009 paper [4] they measure a snooker cushion height of 36 mm against a 26 mm ball radius and describe this as "close to the height of 1.4 times ball radius found in pool". 36/26.25 = 1.37, which is close to 1.4 — but the WPA pool figure of 1.27R is not.

This is a genuine inconsistency in the literature that a careful paper should flag. I checked the WPBSA Official Rules of the Games of Snooker and English Billiards (May 2022) directly: it specifies the playing area, the table height from the floor to the top of the cushion rail (864 mm), the ball diameter (52.5 ± 0.05 mm, hence exactly Mathavan's R=26.25 mm), and the ball-weight tolerance — but it does not specify the cushion nose height above the bed at all. So the 1.37–1.4R figure for snooker rests on Mathavan et al.'s single measurement of one Riley Renaissance table, not on a standard, while the 1.27R figure for pool is a written WPA specification.

Possible explanations for the gap: snooker and pool cushion profiles genuinely differ; the measurement datum differs (nose apex versus the point at which a ball of that radius actually touches a curved nose profile — these are not the same point, and for a convex nose the contact point sits below the apex); or one source is in error. I could not resolve it and recommend measuring directly before adopting either value. The sensitivity is not small: sin⁡θ=(h−R)/R is 0.40 at h=1.4R but only 0.27 at h=1.27R — a one-third change in the vertical component of the cushion impulse, and hence in how much topspin the cushion converts.

3.3 The Mathavan–Jackson–Parkin model

The two papers should be read as a pair. The 2009 AJP paper [4] [P] is the experiment; the 2010 IMechE paper [5] [P] is the theory.

Experiment [4]. A single PixeLINK PL-B776F machine-vision camera (3.15 Mpx, up to 1000 fps in ROI mode) mounted vertically above a Riley Renaissance 10×5 ft snooker table, calibrated intrinsically (Bouguet's MATLAB toolbox) and extrinsically to give 1 mm spatial resolution over the table, verified against metre-stick measurements to within 2 mm. Ball centroids extracted per frame; the speed–time plot is the key analytical device, because the change of gradient identifies the sliding-to-rolling transition unambiguously. They report the friction coefficients of §1.7, and for the cushion they restricted themselves to shots played perpendicular to the rail with no sidespin (verified by checking the ball returned along its own path), leaving top/back spin as the only unknown.

Theory [5]. A full 3-D impulse analysis. The independent variable is the accumulated normal impulse PI at the cushion, which is monotonic in time and therefore a legitimate substitute for it [26]. Forces are resolved at the cushion contact I and the table contact C; friction impulses follow Amontons–Coulomb in the instantaneous slip direction Φ(PI) at the cushion and Φ′(PI) at the table, both of which are recomputed at every step. Restitution is imposed through Stronge's energetic coefficient, ee2=−WZ′(PIf−PIc)/WZ′(PIc) — the ratio of work done during restitution to work done during compression — rather than a kinematic velocity ratio, precisely because the kinematic definition is not friction-independent. Integration proceeds in ~5000 steps of ΔPI≈(1+ee)MV0sin⁡α/N.

Calibration. By matching the numerical rebound speeds to the measured perpendicular-incidence data over V0<1.5 m/s, scanning ee and μw over [0,1] in steps of 0.01, they obtain

ee=0.98,μw=0.14

with μs=0.212 for the table contact, M=0.1406 kg, R=26.25 mm.

Validity limit. Numerical and experimental rebound speeds agree up to a normal incident velocity of 2.5 m/s, beyond which they diverge — this is where the rigid-cushion assumption fails and the rubber begins to deform substantially and the ball to "sink" into it [5]. For a simulator this is an important and rarely quoted number: below ~2.5 m/s normal component, a rigid-cushion impulse model is defensible; above it, it is not.

Predictions. From their Figures 8–10: - Rebound angle for a rolling ball with no sidespin is independent of incident speed and depends only on incident angle. (Speed affects the rebound speed, not the angle, in this case.) - Speed loss is greatest for incident angles around 40°. - Overspin raises the rebound speed; at ω0T=2V0/R and normal incidence the rebound speed equals the incident speed. Excess topspin has little effect on the rebound angle. - Sidespin has a large effect on both. With "right" spin the rebound speed can exceed the incident speed (energy coming out of the spin reservoir). With strong left spin at incident angles near 90°, the ball rebounds back to the side it came from — an effect described qualitatively in the billiards literature by Walker [16] and analysed in a general ball-bounce context by Cross [32] [P], whose tennis-ball measurements near normal incidence show the same phenomenon.

Acknowledged limitation. The model is not validated against measured spin, only against speeds and angles, because their vision system could not track ball rotation. They recommend a coloured pattern on a white cue ball for future work. As far as I can determine, that validation has not been published, which means the cushion model's spin predictions remain theoretically derived but experimentally unconfirmed.

3.4 Angle- and speed-dependent restitution: three different "COR"s

Mathavan et al.'s own numbers illustrate the trap. For perpendicular incidence with a rolling ball over 0.28–3.5 m/s [4]:

These are not competing measurements. 0.818 is a lumped, phenomenological number that includes frictional losses at both contacts and the redistribution of energy into spin; 0.98 is the restitution of the rubber alone once friction has been separated out. The fall-off at higher speeds is attributed to cushion deformation, i.e. to the breakdown of the rigid assumption, not to a genuine velocity-dependent material property [4].

A simulator using a single scalar cushion restitution is therefore implicitly choosing the lumped number, and should expect to be wrong about spin.

3.5 The empirical relations practitioners use

The practitioner literature encodes the same physics as rules of thumb. These are worth knowing because they are what players expect a simulator to reproduce, and because they constitute a free (if coarse) validation suite.

The mirror / equal-angle system. Sight the mirror image of the target through the rail; the crossing point is the aim point [33] [C]. It is a first-order approximation only.

The 70% shallow-angle rule. For kicks nearly parallel to a cushion, Bob Jewett states that "the cue ball comes off the cushion at only 70% of the slope going in if the cue ball is rolling" — i.e. the rebound angle to the cushion is 70% of the incoming angle, not 100% as the mirror predicts, and this holds even with reverse sidespin. Alciatore documents the resulting aiming system [33] [C], which is the mirror system corrected by that factor. Provenance warning: Alciatore's page attributes the statement to a Jewett forum post rather than to a Billiards Digest column; I was unable to locate a primary published measurement behind the 70% figure, so it should be cited as a widely-used practitioner heuristic and not as a measured coefficient. Its physical content is real, though, and consistent with §3.3: at shallow incidence the cushion-parallel component is attenuated by friction while the (small) perpendicular component is largely returned, and a rolling ball's topspin is converted at the cushion in a way that pulls the rebound short.

The diamond system for three-cushion carom is the most elaborate practitioner construction, and unusually it has a peer-reviewed treatment: Cohen, G. L., "Three cushion billiards: notes on the diamond system", Sports Engineering 5(1):43–51, 2002 [132] [P]. A clear, freely available mathematics-outreach exposition is Polster and Ross [34] [C].

Documented qualitative effects [35] [C], all consistent with §3.3: - topspin/follow lengthens the rebound; draw shortens it; - running (natural) english lengthens and speeds up the rebound; reverse english shortens and slows it; - sidespin has minimal effect at shallow angles and maximum effect on a ball driven straight into the rail; - faster shots rebound shorter for a rolling cue ball, because the post-rebound curve is delayed; - the cushion imparts and can reverse spin on the rebounding ball, so transferred sidespin from a cut affects the bank path (outside cuts shorten banks, inside cuts lengthen them); - new, slick cloth and clean balls give longer banks; a bouncier cushion (higher COR) gives shorter rebounds.

That last item is counter-intuitive and is a good sanity check for a simulator: raising cushion restitution should shorten the bank, because it increases the perpendicular component relative to the parallel one.

3.6 What is genuinely open

The cushion is the least-settled part of the classical problem. Specifically open: the nose-height discrepancy (§3.2); the absence of any spin-validated cushion experiment; the behaviour above 2.5 m/s normal velocity, where the rigid-cushion model is known to fail and no published deformable-cushion model exists; and the effect of cloth condition and cushion temperature, which practitioners regard as first-order and for which there is no quantitative literature at all.


4. Pockets and capture

This section is short because the literature is genuinely thin. There is no peer-reviewed treatment of pocket capture dynamics that I could locate. What exists is (a) a standards specification, (b) careful practitioner measurement, and (c) one recent preprint on a tangential question.

4.1 Geometry and terminology

The terms, from the WPA specification [18] [C] and its commentary:

A striking observation, and a caution for anyone modelling snooker specifically: the WPBSA Official Rules [49] [C] contain no numerical pocket dimensions whatsoever. Rule 1(g) reads, in its entirety, "There shall be a pocket at each of the four corners of the table and one each at the middle of the longer sides." Snooker pocket geometry is fixed by separate manufacturer templates rather than by the rules of the game, whereas pool pocket geometry is specified numerically by the WPA. A simulator that wants to be right about snooker pockets must therefore work from a physical template, not from a rulebook.

Practitioner analysis treats pocket difficulty as the product of three factors — mouth width × facing angle × shelf depth — rather than mouth width alone [36] [C], and the shelf is argued to be the most underrated of the three, since a ball entering with too much speed and too little downward momentum can cross the shelf and hit the far jaw.

4.2 Effective pocket size versus approach angle and speed

The most useful data I found are an explicitly experimental practitioner study by Bob Jewett, with Alciatore, reported in Billiards Digest [37] [C]. Their method: a four-ball combination set on ruled paper (four balls so that essentially no spin is transferred to the last ball), aligned to a thread whose angle to the cushion was measured by offsets at two known distances; the paper was translated laterally until the pocketing success rate was 50%, defining the "edge" of the pocket; the difference between the two edges is the effective width at that angle. Two speeds were used, "soft" (ball rolling smoothly) and "firm" (partly sliding).

Their findings, which contradicted both of their own prior theories:

On effective pocket centre, Alciatore's summary [38] [C] reports that the best aim point shifts from the geometric pocket centre by up to about 0.6 in for corner pockets and 0.3 in for side pockets depending on entry angle. Jewett's earlier hypothesis — that the single best target is the intersection of the "rail grooves", the worn lines half a ball out from each cushion nose — turned out to be only approximately right [37].

4.3 Rattling and capture probability

I found no peer-reviewed model of rattling (multiple jaw bounces) or of capture probability. The nearest published items are:

This is a real gap. For a VR engine the practical consequence is that pocket behaviour must be tuned against practitioner data (§4.2) and against the geometry, because there is no model to implement.


5. Simulation approaches

(Sections 5.1–5.7 follow; see the continuation below.)

5.1 Event-driven (analytic) simulation

The defining observation is the one derived in §1.3: during any one motion phase, a billiard ball's acceleration is constant. While sliding, the friction force is fixed in magnitude and direction; while rolling, the rolling resistance is a constant deceleration antiparallel to the (fixed-direction) velocity. Therefore, within a phase,

r(t)=r0+v0t+12a t2,

a quadratic in t with known coefficients. Everything follows from that.

Transition times are linear. Slide ends when ∣u∣ reaches zero, at t=2∣u0∣/(7μsg); roll ends when ∣v∣ reaches zero, at t=∣v0∣/(μrg); vertical-axis spin ends at t=2Rωz0/(5μspg). All closed form.

Ball–ball collision times are quartic. Two balls collide when ∣ri(t)−rj(t)∣=2R. Squaring, and with both r quadratic in t, the difference is quadratic and its squared magnitude is a quartic polynomial in t. Quartics have closed-form roots (Ferrari), so no root-finding iteration is required.

Ball–cushion collision times are at most quadratic, from the ball centre reaching a line offset R from the cushion nose.

Will Leckie and Michael Greenspan turned this into a complete simulator. The work appears in three places:

Their stated contribution is that "the occurrences of all possible events are determined as the roots of polynomials up to fourth order, for which closed-form solutions exist", giving a method that is "both accurate, returning continuous space solutions for both time and space parameters, and efficient, requiring no iterative numerical methods" — and therefore suitable both for game-tree search (where the same shot is evaluated thousands of times) and for robotic pool (where the prediction must be trustworthy). The main loop is: compute every candidate event time, take the earliest, advance every ball analytically to that instant, resolve the event, repeat.

Trade-offs versus time-stepped simulation.

Event-driven Fixed-timestep rigid body
Accuracy within a phase Exact (to the model) O(Δt) or O(Δt2) integration error
Tunnelling Impossible — collisions are solved for, not detected Possible; needs CCD or small steps
Determinism / reproducibility Excellent; the same shot replays bit-identically given the same root solver Good but sensitive to step boundaries and solver iteration order
Cost Proportional to the number of events, not to elapsed time. Very cheap for a settling table Proportional to elapsed time; a slowly-settling table costs as much as a break
Simultaneous / persistent contacts Poor. Resting contact, a cluster of frozen balls, a ball leaning in a pocket jaw all produce event storms Handled naturally by the constraint solver
Extending the model Every new effect needs a new analytic solution Add a force; the integrator copes
Non-sphere geometry, arbitrary meshes Impractical Routine
Coupling to other physics (cue stick as a rigid body, a ball leaving the table) Awkward Natural

The last three rows are the reason a VR engine cannot simply adopt the event-driven approach wholesale: a VR cue is a tracked rigid body moving at arbitrary speed with arbitrary orientation, the player can reach in and knock balls about, and objects leave the table. The event-driven method is at its best in exactly the setting Leckie and Greenspan built it for — a closed system of spheres on a plane with a scripted stroke.

Zeno / event-storm behaviour is the specific failure mode. As a ball settles against a cushion or a jaw, the interval between events collapses toward zero and the simulation can stall. Event-driven billiard simulators handle this with velocity and time thresholds — the analogue of the sleeping criteria discussed in §5.6.

Two open-source implementations document the approach in usable detail:

Kiefl's cushion choice is worth noting: pooltool implements Han's model, not Mathavan's. Han, I., "Dynamics in carom and three cushion billiards", Journal of Mechanical Science and Technology 19(4):976–984, 2005 [46] [P], DOI 10.1007/BF02919180, treats all three problems — motion on the bed, ball–ball collision and ball–cushion collision — within rigid-body mechanics, with a numerical simulation program. Han's cushion model is instantaneous and assumes negligible cushion deformation, parameterised by the contact height ϵ above the ball centre, giving impact angle θ=arcsin⁡(ϵ/R) — structurally the same idealisation as Mathavan et al.'s [5] but resolved algebraically rather than by integrating over the impulse.

Further implementations worth knowing are Zitelli's PoolPhysics [47] [S], a Python event-based simulator on GitHub; Poolimmersion [48] [P] — Silva, Malhadas and Ramires Fernandes, EPCGI 2017 — a graphics-conference paper pairing a physically-based simulation with a simulated-annealing artificial player benchmarked against computational-billiards competition winners; and the GPL projects Billiards [129] and Foobillard++ [130] (§7.4). A caution about the FastFiz link above: it is a rescue archive. The original code vanished from Stanford's billiards site and was recovered from the Internet Archive, and its original authorship and licence are not stated — which is itself a small case study in how fragile this field's software record is.

5.2 Compliant (penalty / smooth) contact — the other main route

The event-driven and impulse-based approaches of §5.1 and §§2.5 and 3.3 all share an assumption: the collision is instantaneous, so the contact is resolved as a jump in velocity and the geometry does not change during it. The alternative is to treat contact as a continuous force that is a function of penetration depth, integrate it with an ordinary ODE solver, and let the collision take real time. This is the "smooth" or "penalty" or "compliant contact" family, and it has been applied to billiards seriously and recently.

The foundational contact law is Hunt, K. H. and Crossley, F. R. E., "Coefficient of Restitution Interpreted as Damping in Vibroimpact", Journal of Applied Mechanics 42(2):440–445, 1975 [50] [P], DOI 10.1115/1.3423596. Their insight was that the usual linear (Kelvin–Voigt) spring–damper contact is physically wrong at the moments that matter: it produces a discontinuous force at first touch (damping force ∝δ˙ is finite when δ=0) and a tensile force at separation, sticking the bodies together. Hunt and Crossley instead made the damping term proportional to the penetration as well as its rate,

FN=Kδn+λ δnδ˙,n=3/2 from Hertz,

so the force vanishes smoothly at both the beginning and the end of contact, and the hysteresis loop in the F–δ plane has physically sensible area. This is the standard reference for compliant contact and is the ancestor of essentially every modern penalty formulation. (A 50th-anniversary retrospective article appears to exist in Mechanism and Machine Theory, 2025, but I exhausted my search budget before confirming its authorship, so it is not listed in the references.)

The billiards application is Gismeros Moreno, R., Corral Abad, E., Meneses Alonso, J., Gómez García, M. J. and Castejón Sisamón, C., "Modelling multiple-simultaneous impact problems with a nonlinear smooth approach: pool/billiard application", Nonlinear Dynamics 107(3):1859–1886, 2022 (online 2021) [52] [P], DOI 10.1007/s11071-021-07117-4. Its argument, and its choice of billiards as the test case, are directly relevant here: the paper is about multiple simultaneous impacts — the case where a cluster of balls is struck and several contacts are live at once, which is exactly where the instantaneous-impulse formulations become ambiguous (there is no unique answer to "which contact resolves first"). Billiards is chosen precisely because the geometry is simple enough that the contact question is isolated.

Their model, as far as I could verify it:

Contact Normal force Friction
Ball–ball Lankarani–Nikravesh [165] [P] (a Hunt–Crossley-family law with hysteresis damping), FN=Kδ3/2+χδ3/2δ˙, n=1.5, cr=0.95 Constant μ=0.06 (attributed in the paper to Threlfall — a name I could not independently verify), or the velocity-dependent exponential form μ(v)=9.951×10−3+0.108 e−1.088v — this is Marlow's fit [19] (§1.7)
Ball–cushion Lankarani–Nikravesh, cr=0.98, taken from Mathavan et al. [5] Ambrósio regularised friction, μ=0.14, again from Mathavan et al. [5]
Ball–cloth Plain Hertz, FN=Kδ3/2, no damping Ambrósio regularised friction with tolerance velocities v0=10−4 m/s, v1=10−3 m/s

The "Ambrósio" friction model is the standard regularisation used in multibody dynamics: the Coulomb force is ramped smoothly from zero to μN as the tangential slip speed rises through v0 to v1, which removes the discontinuity at zero slip that makes stiction impossible to integrate. The two tolerance velocities are the numerical price of smoothness: below v0 the model has no friction at all, so a genuinely static ball is held by nothing.

They validate against three independent things: Alciatore's 30° rule [2] across a range of impact fractions; high-speed video of ball–cushion impacts; and Mathavan et al.'s [4] measured restitution and friction for normal cushion impacts.

Trade-offs against the impulse route.

In favour of compliant contact: multiple simultaneous contacts are handled without arbitration, because every contact simply contributes a force; the contact process is resolved, so quantities that depend on it (the exact slip history, the induced spin) come out of the integration rather than having to be assumed; and it composes naturally with everything else in a general physics engine.

Against: the contact stiffness of a phenolic ball is enormous, so the contact duration is on the order of 10−4 s and the ODE is very stiff. Resolving it demands either a tiny fixed timestep (catastrophic for a 90 Hz VR budget) or an adaptive/implicit integrator (which destroys determinism across machines). Parameters must be chosen for numerical behaviour rather than measured, and the effective restitution then depends on the integrator. This is the reason real-time engines almost universally use impulses instead: an impulse method makes the contact duration a modelling assumption rather than a computational cost.

The honest summary for a VR engine is that compliant contact is the more physically complete formulation and the right one for offline study, and the impulse formulation is the only one that fits a real-time frame budget — so the design question is how much of the compliant model's behaviour can be recovered by an impulse method that is applied carefully (§§5.4–5.8).

5.3 A gap worth naming: nobody has modelled the cushion as a deformable body

Mathavan et al. [5] state that their model is valid only below a normal incident velocity of 2.5 m/s, above which the rubber deforms enough that the rigid-cushion assumption fails — and 2.5 m/s is not a hard shot. Above that threshold there is, as far as I can determine, nothing. I searched specifically for finite-element or hyperelastic modelling of a billiards cushion profile and found none. The comparison is instructive: table tennis rubber has a real FEM/hyperelastic literature, and so do golf balls, tennis balls and footballs, but the billiards cushion — a Mooney–Rivlin-ish gum rubber extrusion with a specific and standardised profile, struck millions of times a year in televised competition — appears never to have been modelled as a deformable continuum in the published literature.

That is a genuine and rather surprising hole, and it is exactly where the practitioner community's strongest claims live: that cushion behaviour varies with rubber age, temperature and humidity, and that different table brands bank measurably differently [35]. None of that is quantified anywhere I can find. A paper that wants to state an open problem in cue-sports physics could not pick a better one.

5.4 The rigid-body contact problem, and why friction makes it hard

Between the analytic extreme (§5.1) and the compliant extreme (§5.2) sits the approach every general-purpose real-time engine actually uses: treat contacts as constraints, solve for the constraint forces or impulses that satisfy them, and integrate.

What "analytical" means, and what it is set against. Baraff introduced this framing to graphics, and his 1989 paper is explicit that the alternatives available at the time were unsatisfactory: earlier work either modelled resting contact as "a series of frequently occurring collisions", or applied "arbitrary penalty forces that acted to separate penetrating bodies" — which he dismisses on the ground that "dynamical correctness of these forces was not a focus". He also notes that classical engineering methods do not transfer, because "these techniques assume that the systems of bodies being analyzed are in equilibrium", which a falling stack is not. Analytical therefore means: solve for the forces that would actually arise under the physics, rather than approximating them with springs or with a train of collisions.

The frictionless problem. At each contact, the normal acceleration is affine in the unknown force magnitudes, d¨i=∑jaijfj+bi, subject to three conditions: contacts only push (fi≥0); bodies do not accelerate into each other (Af≥b); and the force is zero wherever the bodies separate. That last condition is the complementarity condition fid¨i=0, and the system

Af≥b,f≥0,f ⁣⊤ ⁣Af−f ⁣⊤ ⁣b=0

is a linear complementarity problem (LCP), reached in Baraff, D., "Analytical methods for dynamic simulation of non-penetrating rigid bodies", ACM SIGGRAPH Computer Graphics 23(3):223–232, 1989 [152] [P] through a quadratic-programming framing. He is candid about the difficulty even here: "the term f ⁣⊤ ⁣Af is quadratic in fi… Quadratic programming, unlike linear programming, is an NP-hard problem in general." For frictionless contact A is positive semi-definite, so the QP is convex and polynomially solvable in principle, though he notes "no practical polynomial time algorithms are currently known", and warns that "there is no reason to believe that A will remain PSD when friction is added."

With friction it breaks, in two distinct ways. Baraff, D., "Coping with Friction for Non-penetrating Rigid Body Simulation", ACM SIGGRAPH Computer Graphics 25(4):31–41, 1991 [153] [P], settles this. First, convexity is lost: frictionless configurations always admit a valid force set solvable as a convex QP, and although the forces need not be unique, "all valid contact forces yield the same accelerations"; with friction, "the QP associated with a configuration involving dynamic friction is not necessarily convex. The existence of a practical solution method for non-convex QP's is considered unlikely, because solving non-convex QP's is NP-hard." Second, existence is lost: "it has been known for at least a century that configurations of rigid bodies with dynamic friction exist that have no valid set of contact forces. We call such a configuration inconsistent." The dual failure is indeterminacy — several valid force sets giving different accelerations.

The formal result, by reduction from Subset-Sum, is that deciding frictional consistency is NP-complete, and Baraff closes the obvious escape route: even a solver restricted to consistent configurations cannot run in polynomial time unless P = NP. His resolution is to abandon the classical principle of constraints — which insists that constraints be met by non-impulsive forces wherever possible — and to allow impulses at inconsistent configurations, justified by a near-rigid picture in which "contact forces arise as a result of small elastic deformations."

A correction worth recording. It is common to attribute the Painlevé paradox to Baraff's 1991 paper. The paper never uses the word; it cites Löstedt, Erdmann, and Mason and Wang for the inconsistent example. The right citations for the paradox itself are Stewart's SIAM Review survey [169] [P], which ties it to "paradoxical results known at least since Painlevé [C. R. Acad. Sci. Paris, 121 (1895), pp. 112–115]" [171], Stewart's convergence paper [172] [P], and Champneys and Várkonyi's review [170] [P]. The latter also supplies two historical corrections: the effect was first found by Jellett, not Painlevé (who acknowledges this), and Painlevé's own 1895 example was a box on an inclined plane, not the rod. Its mechanism: with a large enough friction coefficient and sufficient normal–tangential coupling, "the effective normal force becomes attractive rather than repulsive", and the system can reach dynamic jam, where "the more it tries to lift off, the more it rotates and digs back down into the surface", resolvable only by an impact without collision — an impulsive jump with no approaching normal velocity.

The practical follow-up. Baraff, D., "Fast Contact Force Computation for Nonpenetrating Rigid Bodies", SIGGRAPH '94 [154] [P], drops the optimisation framing entirely — "by moving to an optimization problem… we necessarily lose sight of the original condition fiai=0 for each contact point. Because of this, we are solving a more general, and thus harder, problem" — and adapts Dantzig's pivoting algorithm for LCPs. It builds the solution one contact at a time, maintaining index sets C (clamped, ai=0, fi≥0) and NC (not clamped, fi=0, ai≥0), and to admit contact n it increases fn by "the smallest scalar s>0 such that increasing f by sΔf causes either an to reach zero, or some index i to move between C and NC" — which is pivoting. The cost is roughly three times a dense Gaussian elimination of the same size, and it extends to mixed static and dynamic friction. His stated motivation is accessibility: simple enough that "nonspecialists in numerical programming can implement them on their own."

Since 1989, 1991 and 1994 are all conference papers, the peer-reviewed journal version of the complexity results is worth citing alongside them: Baraff, D., "Issues in computing contact forces for non-penetrating rigid bodies", Algorithmica 10(2–4):292–352, 1993 [167] [P]. The PhD thesis is Baraff, D., Dynamic Simulation of Non-Penetrating Rigid Bodies, Cornell University TR 92-1275, March 1992 [155] [T], and the canonical tutorial treatment — the clearest statement anywhere of the colliding versus resting contact split — is Witkin, A. and Baraff, D., "Physically Based Modeling: Principles and Practice", SIGGRAPH '97 Course Notes [168] [C].

Two things follow for a cue-sports engine. First, this is a direct method: it computes the contact forces for the whole system at once, which is what you want when a rack is struck. Second, its cost is superlinear in the number of simultaneous contacts and it is not naturally parallel — which is why real-time engines went elsewhere (§5.6).

5.5 Time-stepping complementarity, and impulse-based simulation

Time-stepping complementarity. The insight that dissolves Baraff's difficulty is to stop asking the instantaneous question. An event-driven scheme must locate each impact or transition instant, back the simulation up to it and resolve it — and in the Painlevé and Zeno situations there is either nothing well-defined to resolve or an unbounded number of events to resolve. A time-stepping scheme never isolates an instant: it takes a fixed step and solves one complementarity problem in impulses rather than forces, so impulsive and non-impulsive behaviour are described by the same equations. Stewart and Trinkle put it that the method "does not need to identify explicitly impulsive forces."

The foundational papers are Stewart, D. E. and Trinkle, J. C., "An implicit time-stepping scheme for rigid body dynamics with inelastic collisions and Coulomb friction", International Journal for Numerical Methods in Engineering 39(15):2673–2691, 1996 [156] [P], and Anitescu, M. and Potra, F. A., "Formulating Dynamic Multi-Rigid-Body Contact Problems with Friction as Solvable Linear Complementarity Problems", Nonlinear Dynamics 14(3):231–247, 1997 [157] [P]. The word solvable in the latter title is the point: existence becomes a theorem rather than a hope, because the LCP's block matrix is copositive, so a solution exists and Lemke's algorithm constructs it. The concrete difference between the two is where non-penetration is imposed — Anitescu and Potra replace the position-level linearised constraint with a velocity-level one, n^ ⁣⊤vl+1≥0. Stewart defends the velocity level directly: a position-level condition "behaves as if it had a 'random' coefficient of restitution when impacts occur", because the effective restitution depends on where inside the step the contact happens.

Anitescu's later open-access presentation [174] [P] states the payoff plainly: "We do not perform collision detection. Instead, a noninterpenetration constraint is replaced by its linearization, which… guarantees geometrical constraint stabilization without the need to perform a reduction of the time step to detect new collision or stick-slip transition events." It also frames the field cleanly as "regularization approaches and hard constraint (complementarity) approaches", and shows the LCP scheme is the stiff limit of a regularised (i.e. compliant, §5.2) contact model — which is a satisfying unification of the two families. The mathematical-programming counterpart from the same year is Pang, J.-S. and Trinkle, J. C., Mathematical Programming 73(2):199–226, 1996 [173] [P].

Impulse-based simulation. Mirtich and Canny, "Impulse-based simulation of rigid bodies", I3D '95, pp. 181–188 [158] [P], and Mirtich's Berkeley thesis (1996), invert the picture: there are no contact forces at all. "All contact interactions between bodies are affected through collisions; rolling, sliding, resting, and colliding contact are all modeled in this way", via microcollisions — an infinitesimal collision time with Poisson's hypothesis and Coulomb friction. Its claimed advantages are simplicity, robustness, parallelisability, and efficiency for systems with frequently changing contact modes.

Its weakness is exactly the case a pool table presents. The clearest third-party statement is Guendelman, Bridson and Fedkiw [175] [P], who say their own scheme "correctly models difficult frictional effects without requiring microcollision approximations… (which also use an ad hoc velocity)", and explain the failure: a body at rest with non-zero restitution receives a spurious elastic bounce every step, so "objects sitting on the ground… vibrate as they are incorrectly subjected to a number of elastic collisions. Thus, many authors use ad hoc threshold velocities in an attempt to prune these cases." Under a microcollision model a resting body is never truly still; it buzzes at the threshold. For twenty-two balls at rest between shots, that is disqualifying.

The broad survey covering all of this, and the right single citation for a related-work paragraph, is Bender, Erleben and Trinkle, Computer Graphics Forum 33(1):246–270, 2014 [136] [P].

5.6 Sequential impulses: what game engines actually do, and why it is PGS

The method that displaced direct LCP solvers in games is sequential impulses, from Erin Catto. Its bibliographic status is worth stating precisely because it is often mis-cited: Catto, E., "Iterative Dynamics with Temporal Coherence", Game Developer Conference, 2005 [150] [C] — a GDC talk with an accompanying self-published ~20-page technical article, not peer-reviewed and with no DOI — followed by "Fast and Simple Physics using Sequential Impulses", GDC 2006 [150] [C]. Both are hosted at box2d.org/publications, which is the authority for venue and year.

Catto's 2006 framing is an explicit rejection of the alternatives: "Penalty method? Nope. Linear complementarity (LCP)? Nope. Joint coordinates (Featherstone)? Nope. Particles (Jakobsen)? Nope. Impulses? Bingo!" His diagnosis of why naive impulses fail is that "impulses are good at making things bounce", so people get jitter, then "forget static friction" and "forget stacking." His method is five steps: accept penetration; remember the past (warm starting); apply impulses early and often (iterate); pursue the true impulse (accumulate and clamp the accumulator); update position last.

The normal impulse at a contact is

Pn=max⁡ ⁣(−vrel⋅n^+vbiaskn, 0),kn=1m1+1m2+[I1−1(r1×n^)×r1+I2−1(r2×n^)×r2]⋅n^,

with the friction impulse the same expression along the tangent, clamped to [−μPn, μPn].

The critical detail, and the one most reimplementations get wrong, is step 4. Clamping must be applied to the accumulated impulse and the increment recovered by subtraction:

temp   = ΣPₙ
ΣPₙ    = max(ΣPₙ + ΔPₙ, 0)
ΔPₙ    = ΣPₙ − temp

with the same pattern for friction against [−μΣPn, μΣPn]. Catto states the failure mode of naive per-iteration clamping plainly: "each contact point forgets its impulse history", "each contact point requires that every impulse be positive", and "there is no way to recover from a bad impulse." Allowing negative increments on a non-negative accumulator is what lets the iteration converge to the true global solution instead of oscillating. The "temporal coherence" of the 2005 title is the complementary half: a contact cache keyed by contact-point identifier seeds each contact's multiplier from the previous frame, in O(s) time and O(s+n) space.

Sequential impulses is projected Gauss–Seidel, and three sources say so.

  1. Catto's 2005 article never says "sequential impulses" — it says "We obtain the solution of equation (34) using the Projected Gauss-Seidel (PGS) algorithm. This is an iterative algorithm based on matrix splitting." The 2006 deck then presents the identical algorithm as impulses. The two documents are the equivalence.
  2. Catto states it retrospectively in his "Solver2D" post [177] [C]: he "reframed PGS as Sequential Impulses" after implementing the method in Tomb Raider: Legend, calling it "an easier way to conceptualize and implement a game physics engine".
  3. Coumans, in his GDC 2014 talk [176] [C], states it twice: "A generic form MLCP of Sequential Impulse is basically projected Gauss Seidel", and "In gaming we usually use a variation of a Sequential Impulse (SI) solver or equivalent projected Gauss Seidel (PGS) solver." He adds the useful nuance that SI is the matrix-free form: it is an MLCP solver, but "we don't build an actual 'A' matrix."

Two caveats Catto himself records. His 2005 convergence statement is honest: "According to Cottle, convergence is guaranteed if JB is positive definite. In many typical simulations JB is only positive semi-definite. Nevertheless, we have seen good visual and numerical results in practice." And his 2005 friction is decoupled from the normal force: "In Coulomb's friction law, the static and dynamic friction forces have a magnitude that is bounded by the normal force magnitude. This creates an awkward coupling between the constraint multipliers… Therefore, we use a simpler friction model where the friction force is bounded by a constant value." The 2006 formulation restores the coupling by clamping against μΣPn — which is the version to implement.

Consequences for a pool table. PGS costs one pass per contact per iteration, is trivially incremental (stop early and you get a worse but valid answer), and warm-starts beautifully. Its known weakness is convergence along chains of contacts — the tall-stack problem — which is why shock propagation [163] [P] and mass splitting [159] [P] exist. Coumans documents the practical bound: "When only using 4 to 10 solver iterations, the projected Gauss Seidel numerical method often fails to converge to a proper solution", especially at large mass ratios [176]. On a table, contacts are almost all pairwise and short-lived, so PGS converges quickly — but a frozen rack at the break, and a ball settling into a pocket jaw, are precisely the many-simultaneous-contact case where PGS is weakest and where the compliant formulation of §5.2 was proposed [52].

Bullet's documentation makes the lineage explicit: it "uses its btSequentialImpulseConstraintSolver by default", and its acknowledgements credit "Erin Catto, Blizzard: accumulated impulse in sequential impulse" [141] [C].

5.7 Position error: Baumgarte, split impulses, soft constraints and small steps

A velocity-level solver cannot by itself remove existing penetration, because a velocity constraint says nothing about position. The classical fix is Baumgarte stabilisation — Baumgarte, J., "Stabilization of constraints and integrals of motion in dynamical systems", Computer Methods in Applied Mechanics and Engineering 1(1):1–16, 1972 [151] [P] — which adds a term proportional to the position error to the velocity constraint, so the error obeys a stable ODE. Catto states it as C˙+(β/h)C=0 and gives a tuning recipe that is worth repeating because it is entirely empirical: set the bias factor to zero, raise it until the simulation goes unstable, then use half that [150]. In the contact solver it appears as the bias velocity

vbias=βΔtmax⁡(0, δ−δslop),β∈[0.1, 0.3],

with the slop permitting a small permanent penetration so that resting contacts do not buzz [150].

Baumgarte's defect is that it injects energy: the bias velocity is a real velocity, so a body pushed out of penetration keeps the extra kinetic energy and stacks visibly bounce. Two remedies are standard.

Split impulses / pseudo-velocities. Run a second, parallel integration in a pseudo-velocity used only for position correction and then discarded, so penetration is removed without the body gaining energy. There is no paper; the citable sources are the engine itself and its developers. Bullet's btContactSolverInfo ships m_erp = 0.2 (commented "used as Baumgarte factor"), m_erp2 = 0.2 ("used in Split Impulse"), m_splitImpulse = true (on by default), and m_splitImpulsePenetrationThreshold = -0.04f — so split impulse engages only past 4 cm of penetration [141,142] [C/S]. On the project forum, Dirk Gregorius states flatly that "pseudo velocities and split impulses are the same", and Coumans that "Baumgarte sometimes adds unwanted energy/velocity due to deep penetration correction" [142] [C]. Coumans' GDC 2014 framing is the cleanest one-liner: "we may solve those levels combined (coupled) as in Baumgarte stabilization, or we may solve the velocity and position constraints as two independent problems" [176].

Soft constraints. Catto's GDC 2011 talk [150] [C] derives ODE's CFM and ERP parameters from a damped harmonic oscillator, reparameterised by damping ratio ζ and angular frequency ω rather than raw stiffness and damping — his own account is that he first assumed these were "just hackery without any real mathematical underpinning… but I was wrong". The mapping is γ = CFM (softening) and β = ERP (position feedback), with the implementation caveat that γ must be divided by h when the engine works in impulses rather than forces. The payoff is that a soft constraint is "mathematically… not a spring at all, but rather a modified rigid constraint", hence unconditionally stable inside the solver at any stiffness, unlike an explicit spring. (The ODE manual's own formulas are ERP=hkp/(hkp+kd) and CFM=1/(hkp+kd), with ERP defaulting to 0.2 [191] [C].)

A third line attacks the step size instead of the solver. Macklin et al., "Small Steps in Physics Simulation", SCA 2019 [160] [P], argue that for a fixed compute budget it is better to take many small substeps with few iterations each than few large steps with many iterations, because integrator error rather than solver convergence dominates. The related position-based line is XPBD [161] [P], which makes stiffness independent of iteration count and time step, and Müller et al.'s extended-PBD rigid bodies [162] [P]. Catto's Solver2D study [177] [C] implements and compares eight variants on the same benchmarks — PGS with Baumgarte, PGS with nonlinear Gauss–Seidel position correction, block PGS, soft PGS, and four TGS/XPBD variants — and TGS-Soft became "Soft Step" in Box2D v3.0.

A substepping trap worth naming, because it cost this project real time. If a substep loop divides the frame into N steps of Δt/N but executes only N−1 of them — an easy off-by-one when the accumulator is carried in floating point — the simulation runs at (N−1)/N of real speed, silently and uniformly. It does not present as jitter. It presents as everything being slightly slow, which is very easily misdiagnosed as a friction coefficient needing a tweak.

5.8 The friction cone, its faceting, and how much that costs

Coulomb friction confines the contact force to a cone of half-angle arctan⁡μ about the normal, ∥ft∥≤μfn. This is a second-order cone, and it is what makes the contact problem a nonlinear complementarity problem.

The standard remedy is to facet it. Replace the circular cone by the polyhedral cone generated by {n^+μdi} for m tangent directions, write the friction impulse as Dβ with βi≥0 and ∑iβi≤μcn, and the constraint becomes linear — which is what makes Anitescu and Potra's solvability result possible (§5.5). The direction set must be balanced: for every di there is a dj=−di. Stewart's SIAM Review survey [169] [P] derives the accompanying auxiliary variable λ as the Lagrange multiplier of the maximum-dissipation programme min⁡β (v+) ⁣⊤Dβ subject to ψ(β)≤μcn, giving 0≤λ⊥μcn−ψ(β)≥0. Dimensionally λ is a velocity: in sliding it equals the sliding speed along the best-opposing facet, friction saturates on the cone boundary, and complementarity typically leaves one βi non-zero — "the one which maximizes power dissipation"; in rolling λ=0; in separation it "may take on any positive value… and has no meaningful physical interpretation." (Notation warning for anyone reading across this literature: Stewart, Stewart and Trinkle, and Preclik all use λ for the multiplier and β for the tangential weights, while some graphics course notes use the opposite convention.)

Games take the cheapest version, m=4 — a pyramid — which in a 2-D tangent plane means clamping the two tangential components independently to ±μfn, exactly the form in Catto's slides (§5.6).

What faceting costs is anisotropy, and it has been quantified — on rolling spheres. Le Lidec et al. [178] [R/P] state the mechanism: "the linearization of the second-order cone causes the loss of the isotropy for friction… By choosing the axes for the facets of the pyramid and due to the maximum dissipation principle, it is established that one incidentally biases the friction forces towards the corners", demonstrated with a cube given velocity along x that acquires a spurious y velocity and "deviates from the expected straight-line trajectory."

The directly relevant experiment is Preclik's [179] [T] (a student thesis, not peer-reviewed, but the measurement is the point): 19 spheres launched at 5° increments across a quadrant with an eight-facet cone. "Since for all spheres with initial angles not equal to 0, 45 or 90 degrees there exists no corner of the polyhedral friction cone which exactly opposes the contact velocity, the linear velocity does not decrease straightly towards zero… Particularly for the spheres rolling in the 0, 45 and 90 degree directions the relative contact velocity decreases the fastest." Only five distinct velocity profiles emerge among 19 headings — the pyramid's symmetry group is directly visible in the output. His inclined-plane test, with a facet corner pointing exactly uphill, reproduces μ0=tan⁡θ to five decimals, so the error is purely directional and vanishes on-axis.

This is why the friction cone matters more for cue sports than for most games. §1.3 showed that the entire post-impact trajectory of a cue ball is set by a constant friction force whose direction is the slip direction — and across a game's shots that direction is uniformly distributed over the circle. A solver whose effective friction depends on the heading relative to an arbitrary tangent basis will make the same shot behave differently depending on which way the table happens to be oriented. The corroborating evidence is Bullet's documented rolling-friction bug (§5.10), which is exactly this pathology, and whose accepted fix was to use a true cone. The older standard citations for corner bias are Trinkle et al. [180] [P] and Acary and Brogliato §13.3.7 [166] [B].

Solving the true cone. The reference work is Acary, V. and Brogliato, B., Numerical Methods for Nonsmooth Dynamical Systems: Applications in Mechanics and Electronics, Lecture Notes in Applied and Computational Mechanics vol. 35, Springer, 2008 [166] [B], DOI 10.1007/978-3-540-75392-6. The nonsmooth contact dynamics (NSCD) tradition descending from Moreau and Jean does not facet at all: it is fully implicit, and solves each local one-contact problem against the true cone inside a block Gauss–Seidel sweep. Moreau's foundational chapter [186] [B] introduces the governing idea — that "the velocity is not supposed to be a differentiable function of time, but only to have locally bounded variation, so the role of the acceleration is held by a n-dimensional measure", and dynamics is then governed by measure differential inclusions, "which treat possible velocity jumps on the same footing as smooth motions." The numerical papers are Moreau's sweeping process [187] [P] and Jean's NSCD method [188] [P], which sit in the same 1999 CMAME special issue as Anitescu, Potra and Stewart's three-dimensional time-stepping paper and can be cited as a unit.

Two graphics papers show what the true cone buys and how to get it:

And the true cone need not be expensive, which undercuts the usual justification for faceting. Tasora and Anitescu [185] [C/P] give a closed-form non-expansive cone projection costing a handful of flops per contact: with γr=γu2+γv2, Πn=(γrμ+γn)/(μ2+1), Πr=μΠn, Πu=γuΠr/γr, Πv=γvΠr/γr.

For a ball on cloth there is an even cheaper answer. Because §1.3 proves the slip direction is constant throughout a sliding phase, a 4-direction basis aligned to u^ at the start of the phase stays aligned for the whole phase — so the pyramid's anisotropy costs nothing, provided the basis is chosen from the physics rather than from the world axes. This is, I think, a small but genuinely useful observation that falls out of putting §1.3 and §5.8 next to each other.

One distinction to keep clean, flagged by Le Lidec et al. [178]: Anitescu's convex relaxation has a different artefact from the pyramid's. It permits λN⊥(cN−μ∥cT∥) rather than λN⊥cN, "which results in objects interacting at distance when contact points are sliding." Do not conflate the two errors. Two further routes are worth naming. Kaufman et al.'s staggered projections [190] [P] solve the coupled normal–friction problem by alternating projections onto two convex sets rather than decoupling them, which is the standard reference for treating the coupling properly rather than approximating it away. And Todorov's convex, analytically invertible contact model [164] [P] smooths the contact problem into a convex optimisation that can be inverted — the formulation underlying MuJoCo, and a reminder that "solve the true cone" and "keep the problem convex" are not the same goal.

And as Acary, Brémond and Huber conclude after a systematic comparison [189] [P]: "there is no universal solver."

5.9 Sleeping and deactivation — an absence, not a thin patch

A solver-based engine must decide when to stop simulating a body, both for performance and because an iterative solver leaves residual jitter that never quite reaches zero. The striking finding here is how little of this is published.

Bender, Erleben and Trinkle's Computer Graphics Forum state-of-the-art report [136] [P] is a 39-page survey of the entire field of interactive rigid-body simulation. The word "sleeping" appears in it twice, and "island" not at all — and both mentions are in the benchmarking section, framing sleeping as a defect to test for rather than a technique with published criteria:

"Figure 17: Test-cases that can reveal problems with freezing (sleeping policies). If too aggressive bricks will hang unnaturally in the air."

So the honest statement is stronger than "thinly covered": sleeping and deactivation are essentially absent from the peer-reviewed rigid-body literature. They live in source code, engine manuals and developer forum posts. The nearest published treatment is a book chapter — Lengyel, E., "A Jitter-Tolerant Rigid Body Sleep Condition", in Game Engine Gems 2, A K Peters / CRC Press, 2011 [137] [B] — whose text could not be obtained, so no specific method should be attributed to it.

What exists in practice, and is worth recording because a paper may need to justify its own choice:

A failure mode directly relevant to a pool table. Simulation islands in Bullet are built from broadphase AABB overlap; Coumans notes on the project forum [142] [C] that an over-large world size makes AABBs huge and "everything will be merged into one island". Twenty-two balls plus six cushions merging into a single never-sleeping island is a realistic hazard for exactly this application.

And the observation that ties this back to §5.1. For cue sports specifically, the sleeping problem largely dissolves under an event-driven formulation, because the stopping time is analytic. From the transition times used by pooltool [44,45]:

Δtroll→stop=v0μrg,Δtslide→roll=27∣u0∣μsg,Δtspin→stop=2R ωz05μspg.

You do not need a velocity threshold and a heuristic timer, because you can solve for the instant the ball stops. The generic engine literature has no published sleeping criteria because sleeping is a symptom of solving a general problem approximately; the billiards literature never needed them because the specific problem has a closed form. That contrast is, I think, the single most useful thing this review has to say about engine architecture for cue sports.

5.10 Rolling resistance in general-purpose engines — the models are worse than the physics

§1.4 established that rolling resistance on cloth is well modelled as a constant deceleration μrg, measured at 0.0127–0.0129 for snooker [4]. Reproducing that in a general-purpose engine turns out to be surprisingly hard, and the reasons are documented.

The correct form has a length scale. In the discrete-element-method literature, where rolling resistance has a substantial peer-reviewed treatment, the rolling-resistance moment is limited by

∣Mr∣≤μr Reff Fn,

i.e. coefficient × effective contact radius × normal force. This is the form given in Itasca's PFC documentation [149] [C], following Iwashita and Oda's elastic–plastic rolling-stiffness model [146] [P]. Ai, Chen, Rotter and Ooi [145] [P] review and classify the commonly used DEM rolling-resistance models and propose a more general one, assessing each against benchmark cases in both dynamic and pseudo-static regimes. Wensrich and Katterfeld [147] [P] make the conceptually important point that rolling friction in DEM is often a surrogate for particle shape, not a surface property. Kuhn [148] [P] distinguishes two mechanisms: a contact moment between particles, versus a reduction of the tangential contact force with no moment at all.

Both mainstream game engines omit the radius. Bullet's torsional/rolling friction constraint limits the torque to μ_r · P_n with no radius term, so a 26 mm ball and a 1 m ball behave identically at the same coefficient. Box2D v3.1's rollingResistance is structurally the same — a warm-started angular impulse driving relative ω to zero, clamped to ±μr∑Pn — and also has no radius term. PhysX [140] exposes no rolling friction at all, which is the origin of the perennial "my ball never stops" complaint in the Unity and Unreal ecosystems.

Bullet's own demo advises against using it. The RollingFrictionDemo source comments state that spheres come to rest on a slope using the constraint where damping cannot, but "generally it is best to leave the rolling friction coefficient zero (or close to zero)" [143] [S].

Three documented defects, all of which a cue-sports engine would hit:

  1. Anisotropic curving. Because Bullet's rolling friction torque was not projected onto the tangent basis in the way lateral friction is, a sphere rolled straight only at 0°, 45° and 90° and curved at other headings. Coumans' response on the project tracker was direct: "Rolling friction indeed has an issue. We need to use cone friction for rolling friction (as we do for lateral friction)." Fixed by Bullet PR #2138 in March 2019 [144] [S]. This is the same pyramid-versus-cone anisotropy discussed in §5.8, appearing in the rolling channel.
  2. Spinning friction is silently skipped. In btSequentialImpulseConstraintSolver, both the spinning and rolling rows are nested inside a test on the rolling friction coefficient, so setting spinning friction alone applies nothing. Bullet issue #4188 (opened 2022) remains open [144] [S]. For a cue-sports engine this is precisely the bug that would kill vertical-axis spin decay — the §1.5 effect — while leaving everything else looking correct.
  3. Balls that never stop. A 2014 Bullet forum thread reporting spheres that would not stop rolling on a horizontal plane with both friction and rolling friction set to 1.0 has no resolution [142] [C].

A correction worth recording. It is sometimes said that rolling-resistance implementations can reverse a body's spin or inject energy. I asked for sources on this and none were found; the code contradicts it. Both Bullet and Box2D accumulate a clamped impulse targeting ωrel=0, and because the clamp is applied to the accumulated impulse the constraint can at worst bring ω to zero, never past it. The hazard is real for a naive torque formulation — Guendelman-style schemes guard against it explicitly by preserving sign — but the constraint formulations avoid it by construction. I record this because it is a plausible-sounding claim that turns out not to hold.

Erin Catto and Dirk Gregorius discussed the design on the Bullet forum [142] [C]: Catto proposes a velocity constraint ω2−ω1=0 with the torque limited by coefficient × a length scale × sum of normal forces — explicitly including the length scale both shipped engines omit — and notes that "most people simply use angular damping", while conceding that damping cannot reproduce static rolling friction, nor handle a ball at rest on a platform moving at constant speed.

5.11 Which approach for a VR cue-sports engine

Drawing §§5.1–5.10 together, the three families answer different questions, and a VR cue engine has requirements that cut across them.

Event-driven analytic Impulse solver (SI/PGS) Compliant (penalty)
Accuracy within a phase Exact to the model Integration + solver error Integration error only, but stiff
Cost ∝ number of events ∝ contacts × iterations × steps ∝ steps, and the steps must be tiny
Many simultaneous contacts Poor — event storms Adequate; degrades along chains Best — no arbitration needed
Determinism Excellent Good Poor with adaptive integrators
Arbitrary geometry, a tracked cue, balls off the table Impractical Routine Routine
Real-time at 90 Hz Yes, easily Yes No, for phenolic stiffnesses
Physical completeness of the contact Assumed Assumed Resolved

The tension for VR is specific and, as far as I can tell, unaddressed in the literature. The ball–ball, ball–cloth and ball–cushion parts of the problem are exactly what the event-driven method was built for, and it is both faster and more accurate there than any solver. But a VR engine must also simulate a rigid body under external control at arbitrary velocity — the cue — plus the possibility that the player reaches in and disturbs the table, and that balls leave it. Those are general rigid-body problems with no analytic form.

Two hybrid architectures suggest themselves, neither of which appears to have been published:

  1. Analytic table, impulse cue. Run the balls under the event-driven model, and treat the cue as an external kinematic body that injects an impulse into the analytic system at the moment of contact — a single boundary crossing rather than a coupled simulation. This preserves the accuracy and determinism of §5.1 for everything that determines the shot, at the cost of a special case for the strike itself.
  2. Impulse solver with billiard-specific contact laws. Keep a general SI/PGS solver but replace its contact response with the measured models of §§2 and 3 — the Mathavan cushion impulse [5], the throw model with its 1/7 cap [2] — rather than a generic restitution-plus-Coulomb pair. This buys generality at the cost of having to defeat the solver's own defaults, and inherits the friction-cone anisotropy problem of §5.8 unless the tangent basis is aligned to the slip direction.

Two design constraints follow from the review and are worth stating as such:


6. VR, tracking and embodiment

This section is deliberately short, but every claim in it is load-bearing for a cue-sports engine, because a cue stroke is close to the worst case for a consumer VR tracking system: a fast, self-paced, ballistic motion of a held implement, ending in an impact, whose outcome is determined almost entirely by the state of the implement in the few milliseconds around that impact.

6.1 Motion-to-photon latency: where the numbers come from

The widely quoted "20 ms" target is not a psychophysical result. It comes from Carmack's practitioner article "Latency Mitigation Strategies" (2013) [53] [C], which states that below approximately 20 ms delays "are generally imperceptible" and that 50 ms "will feel responsive, but still noticeably laggy". The same article introduces the mitigation techniques — late input sampling, view bypass, and time warping the rendered frame against updated pose — that are the direct ancestors of asynchronous timewarp, and which are why a device's effective latency is lower than its pipeline latency. Stauffert, Niebling and Latoschik's peer-reviewed review [54] [P] is the right citation for this provenance, because it performs the attribution explicitly rather than repeating 20 ms as folklore.

The psychophysical numbers are different and, for the most part, smaller:

Two cautions. First, absolute detection thresholds in slow manual pointing are far higher than change JNDs during fast motion — Yang et al. [60] [P] report a latency perception threshold of 130–170 ms in a Fitts'-law pointing paradigm, while also showing (via EEG) that latency was registered neurally even when participants were unaware of it. Conflating the two families of number is a common error. Second, Stauffert et al. [54] emphasise that latency jitter — spikes and periodic patterns — provokes cybersickness more reliably than a higher but steady latency does, and that prediction reduces jitter at the cost of over-anticipation artefacts.

6.2 Tracking during rapid implement motion — the critical finding

The single most relevant paper for a VR cue engine is Warburton, Mon-Williams, Mushtaq and Morehead, "Measuring motion-to-photon latency for sensorimotor experiments with virtual reality systems", Behavior Research Methods 55(7):3658–3678, 2023 [61] [P], DOI 10.3758/s13428-022-01983-5. Their point is that previous methods report a single averaged latency and thereby hide the effect of the motion-prediction algorithms in modern runtimes. Using a high-speed-camera technique that co-registers real and virtual controller motion through a movement, on HTC Vive, Oculus Rift, Rift S and Valve Index under Unity + SteamVR, they found:

at the start of a sudden movement, mean latencies of 21–42 ms; once prediction converges, latency falls functionally to 2–13 ms; convergence takes ~25–58 ms from movement onset.

Their own stated implication is that "sudden accelerations (e.g., movement onset, impacts, and direction changes) will increase latencies and lower spatial accuracy." A cue strike is a sudden acceleration terminating in an impact. The shot is decided during the system's worst tracking window.

Two supporting results sharpen this:

The engineering conclusion, which a VR cue-sports engine should probably state as a design principle: derive the strike from tracked velocity at the moment of contact, not from acceleration, and do not trust the pose stream in the frames immediately around movement onset.

On tracking rates: Niehorster, Li and Lappe [65] [P] give the cleanest peer-reviewed account of the architecture — IMU dead reckoning at high rate underneath, lighthouse correction at 120 Hz, application-visible pose consumed at the 90 Hz display refresh — together with an end-to-end latency of about 22 ms measured with a 480 Hz camera, sub-0.03 mm² positional jitter, and the important failure mode that regaining tracking after a loss produces large position and orientation offsets that no one-time calibration can fix. Bauer, Lienhart and Jost [66] [P] independently found systematic errors of several centimetres including a ~0.4° reference-plane tilt on a Vive Pro at a geodetic calibration facility, and Sansone et al. [67] [P] replicated the tilt and found 0.5 ± 0.2 cm accuracy in plane but 1.7 ± 1.2 cm on the depth axis. Kuhlmann de Canaviri et al. [68] [P] confirmed against a UR10 robot that dynamic accuracy "suffers from increasing velocity" and that more base stations help.

Vendor controller sample rates are not published, in any peer-reviewed source or spec sheet I could locate. Any device-specific pose rate a paper relies on is that paper's own measurement and should be presented as such.

6.3 Lag and manual aiming performance

Two older results are worth citing because they establish which lag matters. Ware and Balakrishnan [69] [P] found that lag in head tracking is relatively unimportant for performance, whereas lag in hand tracking is critical, and modelled hand lag as a multiplicative term on Fitts' index of difficulty — so small lags cause large degradation when targets are small, which is the cue-sports case exactly. They also measured higher error along the in/out-of-screen axis, foreshadowing the depth-axis finding above. MacKenzie and Ware [70] [P] quantified it: at 225 ms lag, movement times rose 64% and error rates 214%, and the multiplicative model explained 94% of variance.

Kelkkanen et al. [71] [P] studied hand-controller latency and aiming accuracy directly in 6-DoF VR, finding accuracy degrading beyond ~130 ms latency for predictable target motion and ~90 ms for unpredictable motion — a cue shot is a self-paced aim at a static target, i.e. the forgiving end of that space, which is some comfort.

6.4 Haptics for impact

The canonical reference is Kuchenbecker, Fiene and Niemeyer, "Improving contact realism through event-based haptic feedback", IEEE TVCG 12(2):219–230, 2006 [72] [P]. Their observation — "tapping on surfaces in a typical virtual environment feels like contact with soft foam rather than a hard object" — and their fix, superimposing high-frequency transients scaled by impact velocity on the position-based force, is directly the model a cue-tip-on-ball event wants. In their study, event-based feedback made virtual samples rate as woodlike where position feedback alone rated as foam.

Okamura, Cutkosky and Dennerlein [73] [P] measured stylus acceleration during real tapping, modelled it as a decaying sinusoid, and then found — crucially for implementation — that the most realistic parameters differ from those fitted to the measured acceleration, because display bandwidth limits faithful replay. Tune by perception, not by fitting physics. Choi and Kuchenbecker [74] [P] survey the actuator technology and are the right citation for the hardware ceiling on rendering a strike transient through the LRA in a consumer controller. Lopes, Ion and Baudisch's Impacto [75] [P] shows what full impact rendering would take: decomposing the sensation into a solenoid tap (tactile) plus electrical muscle stimulation (the impulse), rated more realistic than either alone, and explicitly designed to be merged into props such as a bat.

On the weight and inertia of a held virtual implement, the pseudo-haptic literature (Lécuyer [76] [P]; Samad et al. [77] [P]; Ujitoko and Ban [78] [P]) manipulates the control–display ratio to induce perceived weight. For a cue this must be flagged as a tension rather than a solution: distorting hand-position gain is precisely what one must not do during an aimed stroke, and Ujitoko and Ban single out "the visible mismatch between visual stimulus and user input" as an unsolved design problem — which a precision aiming task will expose immediately.

6.5 Embodiment and the tool

Kilteni, Groten and Slater [79] [P] give the standard decomposition: sense of embodiment = self-location + agency + ownership. Waltemate et al. [80] [P] provide the key latency dissociation — in a virtual-mirror task with delays from 45 to 350 ms, motor performance and simultaneity perception degrade above 75 ms, while agency and ownership hold until about 125 ms and do not collapse even at 350 ms. The hand stops working before it stops feeling like yours.

Argelaguet et al. [81] [P] report a counter-intuitive result with direct design consequences: agency is stronger for less visually realistic hand representations, because they produce less mismatch between action and animation, while ownership is stronger for the realistic hand. Applied to a cue, this suggests a schematic, perfectly-tracked implement may outperform a beautifully rendered one that lags.

Weser and Proffitt [82] [P] review tool embodiment and argue that expertise moderates it: experts embody tools differently from novices, and may show enhanced body-representation change when using their own personal tool. For a cue-sports study this makes player skill a variable that must be measured, not controlled away — and it implies a real player's own cue is not interchangeable with a generic virtual one.

6.6 Virtual sports implements: what transfers

The ball-sports VR training literature is small but consistently positive; Richlan et al. [83] [P] review twelve pre/post intervention studies (aggregate N = 493) and Neumann et al. [84] [P] give the earlier systematic review. Miles et al. [85] [P] supply the framing distinction between perceptual fidelity (how the scene looks) and functional fidelity (whether the task behaves right), arguing the latter matters more for sports training — which is an argument for spending engineering effort on physics rather than rendering.

The strongest transfer results are Gray's baseball study [86] [P] — adaptive VE training beat extra real batting practice on an on-field test, and predicted league statistics and competitive level over the following five years — and Michalski et al.'s table tennis study [87] [P] (N = 57, blind expert coach ratings, d≈1.1 for real-world improvement, though against an untrained control). Oagaz, Schoun and Choi [88] [P] provide the necessary nuance: VR table tennis training significantly improved technique but produced no significant change in balls returned at real-world retention. Wu et al.'s SPinPong [89] [P] is the closest analogue to a cue engine — it trains the return of a fast spin shot using a haptic racket, visual cues and temporal distortion.

Two findings deserve special attention because they are cautionary. Harris et al. [90] [P] found that novice golfers trained in VR improved real putting comparably to real practice — but in Experiment 2, skilled golfers who used VR immediately before real putting showed impaired quiet-eye gaze control and worse putting accuracy. VR as a harmful warm-up for experts is a result any cue-sports engine paper should engage with, since a substantial fraction of its users will be real players. Their companion paper [91] [P] sets out the fidelity/validity framework for a putting simulator.

6.7 What exists for cue sports in VR, and what does not

My first pass through this literature concluded that no peer-reviewed HMD cue-sports study existed at all. A second, independent search showed that to be wrong, and the correction is worth recording because the distinction it turns on is exactly the one a VR cue engine has to reason about.

Work that exists. The strongest reference is Haar, S., Sundar, G. and Faisal, A. A., "Embodied virtual reality for the study of real-world motor learning", PLOS ONE 16(1):e0245717, 2021 [95] [P]. Participants hold a real cue and strike a real ball on a real table, while an HTC Vive Pro renders a veridically aligned virtual scene, with OptiTrack streaming the cue pose at 90 Hz. Two things make it directly load-bearing here. First, the rig was validated by comparing real-world ball trajectories against the physics engine's computed virtual trajectories — that is precisely the validation methodology a VR cue engine paper should adopt. Second, the finding is a measured fidelity deficit: learning in embodied VR resembled the real task but was slower and weaker, and intertrial variability showed no short-term learning trend in VR, unlike the real world. Their non-VR baseline is Haar, van Assel and Faisal [96] [P], which instrumented first-time billiards learners with full-body wearables and found motor learning affects the whole body.

Haptics for cue sports has been attempted: Gourishankar, Srimathveeravalli and Kesavadas, "HapStick: A High Fidelity Haptic Simulation for Billiards", World Haptics 2007 [97] [P]; De Paolis, Aloisio and Pulimeno [98] [P], whose XVR implementation is a useful contrast because it drives the balls with a generic rigid-body engine (ODE) rather than a billiards-specific analytic model; and Thai and Kumar [99] [P], a 2×4 mixed-factorial transfer-of-training study (N = 38) on how haptic feedback in a mixed-reality pool game affects real-life pool performance. De Grandpré et al. [100] [P] recorded EEG during virtual pool shots with 30 participants, explicitly motivated by "the lack of realistic sensory feedback from traditional VR controllers".

The augmented-reality line assists play on a physical table: Uchiyama and Saito [92] [P] overlay predicted ball behaviour from a single handheld camera view with no markers or magnetic sensors; Sousa, Alves and Rodrigues [93] [P] project trajectories, effects and menus onto the cloth from a projector-plus-Kinect rig, reporting 98% shot-prediction accuracy when no cushion bounce occurs — a qualifier that says a great deal about the state of cushion modelling (§3.6); Yan, Zhan and Yang [101] [P] present a head-mounted AR billiards learning assistant. Wu and Dellinger [94] [P] describe capturing reality for a billiards simulation with a tangible physical mini-table.

What is still missing. What none of this covers is the case a VR cue-sports engine actually occupies: a fully virtual table, cue and balls, struck with a tracked controller, with the physics entirely simulated. Every study above either keeps the physical equipment (Haar et al.; the real-cue attachments in §7), augments a real table (Uchiyama; Sousa; Yan), or evaluates a haptic device rather than the simulation. Richlan et al.'s review of VR sports training [83] lists archery, bowling, curling, darts, golf, baseball, table tennis, goal sports and martial arts — no cue sport appears at all.

Nor could either search pass find any peer-reviewed evaluation of the physics accuracy of a commercial cue-sports product against real-table measurements (§7.3). So the defensible gap statement is narrower than "nobody has studied VR billiards", but it is still a real one: the perceptual, embodiment and fidelity questions specific to striking a virtual ball with a virtual cue have not been asked, and no published work measures how closely any VR or commercial cue-sports simulation reproduces measured real-table behaviour.


7. Existing billiards simulators, competitions and games

7.1 The academic lineage

The academic simulation work forms a single connected tradition, and it is worth laying out because almost every later system inherits from it.

Queen's University (Greenspan's group) produced the event-based simulator (§5.1) [40,41,42] and the Deep Green robot: a ceiling-mounted industrial gantry over a full-size pool table, integrated with the same physics simulator used in the computational pool tournaments, and described by its authors as playing "at an above-amateur level" [102] [P]. The robotics papers are Long et al. [103] [P] on automatic potting, Greenspan et al. [104] [P] on whether computational intelligence is needed at all, Lam and Greenspan [105] [P] on eye-in-hand visual servoing, and a US patent on dual-camera positional error correction [106] [C] (a global overhead camera locates the balls; a cue-aligned local camera corrects accumulated positioning error). Leckie and Greenspan also applied Monte-Carlo tree search to pool strategy [107] [P].

Stanford (Shoham's group) produced CueCard, the 2008 tournament winner, and the clearest framing papers: Archibald, Altman and Shoham, "Analysis of a Winning Computational Billiards Player", IJCAI-09 [108] [P], and Archibald, Altman, Greenspan and Shoham, "Computational Pool: A New Challenge for Game Theory Pragmatics", AI Magazine 31(4):33–41, 2010 [109] [P]. A distributed follow-up appeared in IEEE TCIAIG in 2016 [110] [P].

Alberta produced PickPocket — Smith, M., "PickPocket: A computer billiards shark", Artificial Intelligence 171(16–17):1069–1091, 2007 [111] [P], and the earlier AAAI paper [112] [P]. PickPocket won the simulated 8-ball tournaments at the 10th and 11th Computer Olympiads by adapting classical game-tree search to a continuous, stochastic domain.

Other approaches: Landry and Dussault's optimisation-based player [113] [P]; Chua, Wong and Koo's zero-order Sugeno fuzzy decision system [114] [P] (note the title often mis-cited as "Decision algorithm for pool using fuzzy system"); reinforcement learning at macro and micro scales [115] [P]; backward induction plus machine learning for a "human-like" bot [116] [P]; and Fragkiadaki et al.'s visual predictive models, which used billiards as the test domain for learning physics from pixels [117] [R/P].

The most recent and most relevant to a modern engine is CueTip — Memery, S. et al., "CueTip: An Interactive and Explainable Physics-aware Pool Assistant", SIGGRAPH '25 Conference Papers, 2025 [118] [P]. It builds its environment on top of pooltool [44], instrumenting the simulator to emit natural-language event traces alongside state traces for an LLM to interpret, with a trained MLP surrogate to keep interaction fast. It is a clear demonstration that the event-based lineage remains the substrate researchers reach for.

Also worth knowing: a robotic snooker player at Bristol dating to the late 1980s (the "Snooker Machine"), which led to Sang's 1994 PhD thesis [119] [T]; Ho, Martin and Baldwin's twenty-years-on retrospective [120] [P]; Nierhoff, Heunisch and Hirche on strategic play [121] [P]; and the computer-vision line from Denman, Rea and Kokaram's snooker broadcast analysis [122] [P] to Rodriguez-Lozano et al.'s 3-D reconstruction and multi-object tracking [123] [P].

7.2 The Computational Pool Tournament — and its shot parameterisation

The competitive series is directly useful for a VR engine because it settled a shot representation and a noise model, both of which map onto the VR input problem.

The game was 8-ball under Billiards Congress of America rules [109]. The architecture was client-server: the server holds the virtual table state and executes submitted shots on the PoolFiz simulator, with a 10-minute per-game budget per agent. FastFiz [43] is the later re-implementation; note a discrepancy in the sources — the JOSS paper describes FastFiz as "custom built for hosting the AAAI Computational Pool Tournament from 2005–2008" [44], while the AI Magazine article and FastFiz's own archive README indicate PoolFiz ran the 2005/2006/2008 events with FastFiz succeeding it ahead of 2011. I flag this rather than picking a side.

The shot is five real numbers [109]:

Symbol Meaning Units
v cue velocity m/s
ϕ cue orientation (azimuth) degrees
θ cue elevation above the table degrees
a horizontal offset of the tip impact point from ball centre mm
b vertical offset of the tip impact point from ball centre mm

Because the simulator is deterministic, human fallibility was modelled by adding zero-mean Gaussian noise on the server side, with standard deviations of 0.1 for θ, 0.125 for ϕ, 0.075 for v, and 0.5 for a and b [109]. This is a genuinely useful reference point for a VR engine: it is a published, competition-validated estimate of how much a shot's five parameters have to be perturbed to represent a less-than-perfect player — and it is directly comparable to the tracking-error budget of §6.2. A VR system whose tracking noise exceeds the tournament's skill noise is, in effect, playing for the user.

One further detail from the IJCAI-09 paper: CueCard used its own re-implemented physics engine giving an average six-fold speedup per simulation, validated by checking that a shot simulated on both engines landed sufficiently close [108]. The theme recurs — every serious system ends up rewriting the physics for speed and then has to answer the validation question.

7.3 Commercial and VR products, and what they claim

Everything in this subsection that touches physics quality is vendor marketing. Neither research pass found any technical documentation, whitepaper, patent, or published model for any commercial cue-sports physics engine. The claims are listed because a related-work section should record what the field asserts about itself, not because they are evidence.

Non-VR simulators.

VR titles. Corrections to several titles in common circulation: there is no "Sports Bar VR 2" (only a version 2.0 update in December 2017); the ForeVR title is ForeVR Pool, not "ForeVR Billiards"; and no "Snooker VR" or "Snooker 22" product exists.

Title Developer / publisher Released Physics claim (vendor)
Sports Bar VR (formerly Pool Nation VR) Cherry Pop Games + Perilous Orbit Jun 2016 (Steam), Oct 2016 (PSVR) "an immersive and accurate representation of the sport… real pool physics"; "world renowned Physics engine… the balls will behave as they would in the real world"
ForeVR Pool ForeVR Games May 2023 (Steam), Dec 2023 (PSVR2) "ForeVR's custom Pool physics engine, tailored for all play styles—spins, jumps, and trick shots included"
MiRacle Pool Pixel Works Jun 2024 (Quest) "VR's #1 Pool Simulator"; "the most realistic ball physics"; "physics-first"; physics "developed over three years"; Arcade vs Simulation modes
Backspin: Snooker & Pool Portus Labs Jan 2026 (Quest) "spin-true cue ball physics, realistic throw, and natural table roll"; tables "tuned to real dimensions and authentic pocket geometry"; Real Cue Mode to play with a physical cue
Unlimited Snooker SP Software Productions Jun 2025 (Quest) "Novel table alignment system"; "Real Cue Attachment. Play with your own cue exactly like you do in real life"
Cueist / Cueist 2 (developer unconfirmed) — "not a casual point and click type game, but a deeper simulation which will reward real skill"; supports "spin, swerve, massé, and jump shots"
Snooker Billiard DotStudio Jul 2026 (SteamVR) "a custom-designed dedicated physics engine"; ray tracing in VR
Hustle Kings VR XDev Studio Europe 2016 (PSVR) makes no physics claim

Two patterns in that table are worth noting for a paper. First, every product that competes on fidelity claims a bespoke physics engine — none claims to use a general-purpose rigid-body engine, which is at least consistent with the argument of §5. Second, the newest titles converge on attaching a real physical cue to a tracked controller (Backspin's "Real Cue Mode", Unlimited Snooker's "Real Cue Attachment"). That is an implicit admission that controller-held virtual cues have a fidelity problem, and it aligns with Weser and Proffitt's finding [82] that experts embody their own tools.

7.4 Open-source implementations

Project Language / licence Physics Notes
pooltool [44] Python, Apache-2.0 Event-based (Leckie–Greenspan); Han cushion model; Numba JIT; Panda3D 3-D UI The only one with a peer-reviewed paper; also peer-reviewed by pyOpenSci. Extensively documented [10,45]
FastFiz [43] C++ with Python bindings Successor to PoolFiz; FastFiz.h (table physics, rules-independent) + Rules.h (8-ball etc.) A rescue archive: the original code vanished from Stanford's billiards site and was recovered from the Wayback Machine. Original authorship and licence are not stated
Billiards (nongnu) [129] Lua 5.1 on the Techne framework, GPL "aims for physical accuracy and simplicity", "totally configurable" Candid about limits: no jump shots, and the author states he is "not a particularly experienced billiards player" and invites feedback on the model. No Windows support
Foobillard++ [130] C, GPL Not documented Enhanced fork of Berger's foobillard; Linux + Windows
PoolPhysics [47] Python Event-based Not independently assessed

7.5 Two genuine gaps in this area

No peer-reviewed evaluation of any commercial cue-sports product exists — not of its physics accuracy against real-table data, and not as an experimental apparatus in a user study. The nearest citable statements are the JOSS paper's peer-reviewed concession that "realistic physics [is] seen in some commercially-produced games (i.e., Shooterspool and VirtualPool4)" but that they "have little, if any, utility in research contexts due to closed source code and a lack of open APIs" [44]; and Alciatore's expert-practitioner assessment that "modern pool simulators like Virtual Pool do surprisingly well at matching the physics and play of a real pool table; although, they are not perfect" [131] [C] — offered without measurement data.

No differentiable billiards simulator has been published. Both research passes searched for one and found only general differentiable-physics and RL work with no billiards application. Given how well-suited the domain is — a low-dimensional, five-parameter action space with an analytic forward model — this is a conspicuous absence rather than a saturated area.


8. What is settled, and what is open

8.1 Settled

These can be stated in a paper without hedging, and an engine that disagrees with them is wrong.

8.2 Open, or thinly covered

Ordered roughly by how much a VR cue engine would benefit from an answer.

  1. Cushion behaviour above ~2.5 m/s normal velocity. The rigid-cushion model is known to fail there [5] and nothing replaces it. No finite-element or hyperelastic model of a billiards cushion profile appears to exist, despite comparable literatures for table-tennis rubber, golf balls and tennis balls (§5.3). This is the largest single hole in cue-sports physics.
  2. Spin validation of the cushion model. Mathavan et al. [5] explicitly flag that their model is validated against speeds and angles only, and recommend a patterned cue ball to track rotation. That experiment does not appear to have been published.
  3. Cushion nose height. 1.27R (WPA specification) versus 1.37–1.4R (Mathavan's single measurement of one snooker table); the WPBSA rules specify no cushion height at all [49]. The parameter changes the vertical impulse component by a third (§3.2).
  4. Pocket capture and rattling. No peer-reviewed model exists. The only quantitative data are Jewett and Alciatore's practitioner measurements of effective pocket width against approach angle and speed [37,38], and those overturned both authors' prior theories. Snooker pocket geometry is not even specified in the rules [49].
  5. The effect of cloth condition, temperature and humidity. Practitioners treat these as first-order [35]; there is no quantitative literature.
  6. Ball–ball friction. Marlow's exponential speed dependence [19] is used by everyone (Alciatore [2], Gismeros Moreno et al. [52]) while Mathavan et al. [17] judge the experiment behind it unreliable and prefer a constant 0.05. Nobody has redone the measurement with modern instrumentation.
  7. Whether translation and vertical-axis spin genuinely stop simultaneously on cloth, as they provably do for a uniform disk. Mathavan et al. [4] observe it; nobody has proved or measured it properly.
  8. Differentiable billiards simulation. Searched for by two independent research passes; nothing found. The domain is unusually well suited to it — a five-parameter action space with an analytic forward model (§7.2).
  9. Fully virtual VR cue sports. No peer-reviewed study of a VR simulator with a virtual table, virtual cue and virtual balls. The existing VR billiards literature keeps the physical equipment [95,96], augments a real table [92,93,101], or evaluates a haptic device [97,98,99] (§6.7).
  10. Physics validation of any commercial or VR cue-sports product. No published measurement of any product's ball behaviour against real-table data. The strongest available statements are a peer-reviewed aside [44] and an expert opinion offered without data [131] (§7.5).
  11. Controller pose sample rates are not published by vendors or in the peer-reviewed literature (§6.2); any figure a paper uses is its own measurement.
  12. Sleeping and deactivation criteria are essentially absent from the peer-reviewed rigid-body literature (§5.9). A 39-page state-of-the-art report [136] mentions sleeping twice, both times as a defect to test for. What exists lives in source code and one book chapter whose text I could not obtain [137].
  13. Rolling resistance in shipped game engines omits the effective contact radius that the DEM literature requires [145,146,149], Bullet skips spinning friction unless rolling friction is also non-zero (an open issue since 2022), and Bullet's own demo advises against using its rolling friction at all (§5.10).
  14. No published architecture combines an event-driven table with a solver-driven cue. The hybrid a VR cue engine needs — analytic ball dynamics coupled to a general rigid body under external control — does not appear in the literature (§5.11).

8.3 Claims in this review I could not verify

Listed so they are not accidentally propagated.


References

Source types: [P] peer-reviewed paper · [B] book · [T] thesis · [R] preprint/technical report · [C] practitioner or standards resource · [S] software · [V] vendor claim.

Numbering follows first citation within each of four research passes (classical physics and cushions; simulators, games and competitions; VR, tracking and haptics; rigid-body contact solvers), so it is grouped by topic and is not strictly monotonic through the document. Reference 51 was withdrawn during drafting and the number is unused.

Classical billiard physics

  1. Coriolis, G.-G. Théorie mathématique des effets du jeu de billard. Paris: Carilian-Goeury, 1835. 208 pp. [B] — Scanned first edition, Bibliothèque nationale de France: https://gallica.bnf.fr/ark:/12148/bpt6k29318f (I verified the chapter list and pagination directly from this scan.) A further mirror: https://phyweb.phys.soton.ac.uk/quantum/lectures/cm/Coriolis%20billiards.pdf
  2. Alciatore, D. G. "Pool and Billiards Physics Principles by Coriolis and Others." August 2008. [C] https://drdavepoolinfo.com/physics_articles/Alciatore_pool_physics_article.pdf — Caveat: the document is formatted as an American Journal of Physics submission (MS22090) and is cited by Mathavan et al. [5] as "submitted", but I found no evidence it was ever published in AJP. Cite it as a self-published technical article by a mechanical-engineering professor, not as a journal paper.
  3. Nadler, D. Mathematical Theory of Spin, Friction, and Collision in the Game of Billiards. English translation of Coriolis (1835), 2005. [B]
  4. Mathavan, S., Jackson, M. R. and Parkin, R. M. "Application of high-speed imaging to determine the dynamics of billiards." American Journal of Physics 77(9):788–794, 2009. DOI 10.1119/1.3157159 [P] — full text read: https://drdavepoolinfo.com/physics_articles/ajp_09_hsv_article.pdf
  5. Mathavan, S., Jackson, M. R. and Parkin, R. M. "A theoretical analysis of billiard ball dynamics under cushion impacts." Proceedings of the Institution of Mechanical Engineers, Part C: Journal of Mechanical Engineering Science 224(9):1863–1873, 2010. DOI 10.1243/09544062JMES1964 [P] — full text read: https://drdavepoolinfo.com/physics_articles/Mathavan_IMechE_2010.pdf
  6. Shepard, R. Amateur Physics for the Amateur Pool Player, 3rd edition, 1997. [C] https://drdavepoolinfo.com/physics_articles/Shepard_apapp.pdf — self-published monograph by a computational chemist at Argonne National Laboratory; careful, derivation-led, and widely used.
  7. Salazar, A. and Sánchez-Lavega, A. "Motion of a ball on a rough horizontal surface after being struck by a tapering rod." European Journal of Physics 11:228–232, 1990. [P] — verified via the reference list of [4]; not independently retrieved.
  8. Hierrezuelo, J. and Carnero, C. "Sliding and rolling: The physics of a rolling ball." Physics Education 30(3):177–182, 1995. [P]
  9. Doménech, A., Doménech, T. and Cebrián, J. "Introduction to the study of rolling friction." American Journal of Physics 55(3):231–235, 1987. [P]
  10. Kiefl, E. "The physics of pool/billiards." 2020. [C/S] https://ekiefl.github.io/2020/04/24/pooltool-theory/
  11. Alciatore, D. G. "Approximate values for all pool/billiards-related physical properties." [C] https://drdavepoolinfo.com/faq/physics/physical-properties/
  12. Voyenli, K. and Eriksen, E. "On the motion of an ice hockey puck." American Journal of Physics 53(12):1149–1153, 1985. [P] — verified via [4]'s reference list.
  13. Shepard, R. "Everything You Always Wanted to Know About Cue Ball Squirt, but Were Afraid to Ask." 2001. [C] https://drdavepoolinfo.com/physics_articles/Shepard_squirt.pdf
  14. Cross, R. "Cue and ball deflection (or 'squirt') in billiards." American Journal of Physics 76(3):205–212, 2008. [P]
  15. Kim, H.-C. "Motions of a Billiard Ball After a Cue Stroke." New Physics: Sae Mulli 72(3):208–223, 2022. DOI 10.3938/npsm.72.208. Preprint arXiv:2104.11232. [P] — single-authored.
  16. Walker, J. "The physics of the follow, the draw and the massé (in billiards and pool)." Scientific American 249(1):124–129, 1983. [C] — popular-science article; the standard popular exposition.
  17. Mathavan, S., Jackson, M. R. and Parkin, R. M. "Numerical simulations of the frictional collisions of solid balls on a rough surface." Sports Engineering 17(4):227–237, 2014. DOI 10.1007/s12283-014-0158-y [P] — full text read: https://drdavepoolinfo.com/physics_articles/Mathavan_Sports_2014.pdf
  18. World Pool-Billiard Association. Tournament Table & Equipment Specifications / Recommended Equipment Specifications (effective November 2001, as revised). [C] https://wpapool.com/wp-content/uploads/2024/01/RECOMMENDED-EQUIPMENT-SPECIFICATIONS.pdf
  19. Marlow, W. C. The Physics of Pocket Billiards. MAST (Marlow Advanced Systems Technologies), Palm Beach Gardens, FL, 1994/1995. [B] — self-published; the most-cited single source for billiard coefficients, and the one the modern measurement papers most often contradict.
  20. Witters, J. and Duymelinck, D. "Rolling and sliding resistive forces on balls moving on a flat surface." American Journal of Physics 54(1):80–83, 1986. [P]
  21. Wallace, R. E. and Schroeder, M. C. "Analysis of billiard ball collisions in two dimensions." American Journal of Physics 56(9):815–819, 1988. [P] https://pubs.aip.org/aapt/ajp/article/56/9/815/1039419
  22. Onoda, G. "Comment on 'Analysis of billiard ball collisions in two dimensions'." American Journal of Physics 57(5):476–478, 1989. [P]
  23. Jewett, B. "Seeking truth of beliefs." Tech Talk, Billiards Digest, pp. 30–32, June 1995. [C] — the source of the throw dataset reproduced by Alciatore [2].
  24. Alciatore, D. "Throw – Part II: results." Dr. Dave's Illustrated Principles, Billiards Digest 29(10), September 2006. [C] https://drdavepoolinfo.com/bd_articles/2006/sept06.pdf
  25. Alciatore, D. "Throw – Part III: follow and draw effects." Billiards Digest 29(11), October 2006. [C]
  26. Stronge, W. J. Impact Mechanics. Cambridge University Press, 2000. [B] — the source of the energetic coefficient of restitution used by [5] and [17].
  27. Doménech, A. "Non-smooth modelling of billiard- and superbilliard-ball collisions." International Journal of Mechanical Sciences 50(4):752–763, 2008. [P] https://www.sciencedirect.com/science/article/abs/pii/S0020740307001944
  28. Doménech-Carbó, A. "Independent friction-restitution description of billiard ball collisions." Mechanics Research Communications, 2023. [P] https://www.sciencedirect.com/science/article/pii/S0093641323001076 — volume and page numbers unverified; confirm before citing.
  29. Peskin, C. S. "Collision of Billiard Balls in 3D with Spin and Friction." 25 September 2020. [R] https://math.nyu.edu/~peskin/Collision_of_Billiard_Balls_in_3D_with_Spin_and_Friction.pdf — self-hosted technical note by a Courant Institute professor; not peer reviewed.
  30. Kim, H.-C. "Collision of Two Spinning Billiard Balls and the Role of Table." New Physics: Sae Mulli 74(6):621–633, 2024. DOI 10.3938/npsm.74.621. Preprint arXiv:2402.13258. [P] — single-authored. My first pass recorded this as an unpublished preprint; the second pass confirmed publication.
  31. Alciatore, D. "Pool Table Cushion Nose Height Effects." [C] https://drdavepoolinfo.com/faq/table/cushion-nose-height/
  32. Cross, R. "Bounce of a spinning ball near normal incidence." American Journal of Physics 73(10):914–920, 2005. DOI 10.1119/1.2008299 [P] — author copy: https://www.physics.usyd.edu.au/~cross/PUBLICATIONS/31.%20Spin.pdf
  33. Alciatore, D. "Shallow Angle Contact-Point Mirror Kick System." [C] https://drdavepoolinfo.com/faq/bank-kick/contact-point-mirror/ — the source of the "70% of the slope going in" statement, itself attributed there to a forum post by Bob Jewett rather than to a published column.
  34. Polster, B. and Ross, M. "Notes on the Diamond System for playing Three-Cushion Billiards", excerpt from Nitpicking in Mathmagic Land. [C] https://www.qedcat.com/misc/billiards.pdf — mathematics-outreach exposition; clear and correct on the geometry, not a physics measurement.
  35. Alciatore, D. "Bank and Kick Physics Effects." [C] https://drdavepoolinfo.com/faq/bank-kick/effects/
  36. Pool Table Portfolio. "The Shelf Effect: Why Pocket Depth Changes Everything." [C] https://pooltableportfolio.com/blogs/magazine/the-shelf-effect-why-pocket-depth-changes-everything — a retailer's technical blog; used only for the mouth/facing/shelf terminology and typical dimension ranges, which agree with [18].
  37. Jewett, B. "Where's the Pocket? They change size and shape." Billiards Digest, May 2013. [C] https://drdavepoolinfo.com/bd_articles/jewett_may_2013_pocket_size_part1.pdf — full text read; reports the joint Jewett–Alciatore pocket-width measurements.
  38. Alciatore, D. "Pocket Effective Size and Center." [C] https://drdavepoolinfo.com/faq/pocket/size-and-center/ — cites Billiards Digest "Just How Big are the Pockets, Anyway – Parts I–III" (November 2004 – January 2005) and technical proofs TP 3.5 and TP 3.6.
  39. Kantor, A. "One Shot, Twenty-One Balls: Existence and Rarity of a Total Clearance in a Single Stroke of Snooker." arXiv:2607.12995, July 2026. [R] — preprint, not peer reviewed.
  40. World Professional Billiards and Snooker Association. Official Rules of the Games of Snooker and English Billiards, May 2022 revision. [C] https://wpbsa.com/wp-content/uploads/Rulebook-Website-Updated-May-2022-2.pdf — full text read; the source for the 52.5 ± 0.05 mm ball diameter, and for the observation that no cushion height or pocket dimension is specified.

Simulation of billiards

  1. Leckie, W. and Greenspan, M. "Pool Physics Simulation by Event Prediction 1: Motion Transitions." ICGA Journal 28(4):214–222, 2005. DOI 10.3233/ICG-2005-28403 [P]
  2. Leckie, W. and Greenspan, M. "Pool Physics Simulation by Event Prediction 2: Collisions." ICGA Journal 29(1):24–31, 2006. DOI 10.3233/ICG-2006-29103 [P]
  3. Leckie, W. and Greenspan, M. "An Event-Based Pool Physics Simulator." In Advances in Computer Games (ACG 2005), LNCS 4250, pp. 247–262. Springer, 2006. DOI 10.1007/11922155_19 [P]
  4. FastFiz. [S] https://github.com/ekiefl/FastFiz — a rescue archive: the original code disappeared from Stanford's billiards site and was recovered from the Wayback Machine. Successor to PoolFiz, the simulator used for the computational pool tournaments. Original authorship and licence are not stated in the archive.
  5. Kiefl, E. "Pooltool: A Python package for realistic billiards simulation." Journal of Open Source Software 9(101):7301, 2024. DOI 10.21105/joss.07301 [P/S] — full text read. Software: https://github.com/ekiefl/pooltool
  6. Kiefl, E. "The algorithmic theory behind pool/billiards simulation." 2020. [C] https://ekiefl.github.io/2020/12/20/pooltool-alg/
  7. Han, I. "Dynamics in carom and three cushion billiards." Journal of Mechanical Science and Technology 19(4):976–984, 2005. DOI 10.1007/BF02919180 [P]
  8. Zitelli, J. PoolPhysics — event-based billiards physics simulator. [S] https://github.com/jzitelli/PoolPhysics/
  9. Silva, A., Malhadas, D. and Ramires Fernandes, A. "Poolimmersion: A realistic physically-based billiards simulation." 2017 24th Encontro Português de Computação Gráfica e Interação (EPCGI), pp. 1–8. IEEE. DOI 10.1109/EPCGI.2017.8124318 [P]
  10. Hunt, K. H. and Crossley, F. R. E. "Coefficient of Restitution Interpreted as Damping in Vibroimpact." Journal of Applied Mechanics 42(2):440–445, 1975. DOI 10.1115/1.3423596 [P]
  11. Gismeros Moreno, R., Corral Abad, E., Meneses Alonso, J., Gómez García, M. J. and Castejón Sisamón, C. "Modelling multiple-simultaneous impact problems with a nonlinear smooth approach: pool/billiard application." Nonlinear Dynamics 107(3):1859–1886, 2022 (published online December 2021). DOI 10.1007/s11071-021-07117-4 [P]

(Reference 51 was withdrawn: see §5.2.)

VR: latency, tracking, haptics, embodiment

  1. Carmack, J. "Latency Mitigation Strategies." Originally #AltDevBlogADay, February 2013. [C] — practitioner blog; the actual origin of the "20 ms" target. Verified mirror: https://danluu.com/latency-mitigation/
  2. Stauffert, J.-P., Niebling, F. and Latoschik, M. E. "Latency and Cybersickness: Impact, Causes, and Measures. A Review." Frontiers in Virtual Reality 1:582204, 2020. DOI 10.3389/frvir.2020.582204 [P] — open access; cite this for the provenance of the 20 ms figure and for the latency-jitter argument.
  3. Ellis, S. R., Young, M. J., Adelstein, B. D. and Ehrlich, S. M. "Discrimination of Changes of Latency during Voluntary Hand Movement of Virtual Objects." Proceedings of the Human Factors and Ergonomics Society Annual Meeting 43(22):1182–1186, 1999. DOI 10.1177/154193129904302203 [P]
  4. Adelstein, B. D., Lee, T. G. and Ellis, S. R. "Head Tracking Latency in Virtual Environments: Psychophysics and a Model." Proceedings of the Human Factors and Ergonomics Society Annual Meeting 47(20):2083–2087, 2003. DOI 10.1177/154193120304702001 [P]
  5. Mania, K., Adelstein, B. D., Ellis, S. R. and Hill, M. I. "Perceptual sensitivity to head tracking latency in virtual environments with varying degrees of scene complexity." Proceedings of APGV '04, pp. 39–47. DOI 10.1145/1012551.1012559 [P]
  6. Allison, R. S., Harris, L. R., Jenkin, M., Jasiobedzka, U. and Zacher, J. E. "Tolerance of temporal delay in virtual environments." Proceedings of IEEE Virtual Reality 2001, pp. 247–254. DOI 10.1109/VR.2001.913793 [P]
  7. Jerald, J. Scene-Motion- and Latency-Perception Thresholds for Head-Mounted Displays. PhD dissertation, University of North Carolina at Chapel Hill, 2010 (UNC TR 10-013). [T] https://www.cs.unc.edu/techreports/10-013.pdf — the peer-reviewed core is Jerald & Whitton, "Relating Scene-Motion Thresholds to Latency Thresholds for Head-Mounted Displays", IEEE VR 2009, pp. 211–218, DOI 10.1109/VR.2009.4811025.
  8. Yang, S., Yue, K., Gao, H., Guo, M., Liu, Y., Zhang, D. and Liu, Y. "Dynamic Changes of Latency Perception Threshold in Virtual Reality: Behavioral and EEG Evidence." IEEE Transactions on Visualization and Computer Graphics 31(12):10340–10355, 2025. DOI 10.1109/TVCG.2025.3596919 [P]
  9. Warburton, M., Mon-Williams, M., Mushtaq, F. and Morehead, J. R. "Measuring motion-to-photon latency for sensorimotor experiments with virtual reality systems." Behavior Research Methods 55(7):3658–3678, 2023. DOI 10.3758/s13428-022-01983-5 [P] — open access.
  10. Borzelli, D., Boarini, V. and Casile, A. "A quantitative assessment of the hand kinematic features estimated by the Oculus Quest 2." Scientific Reports 15(1):8842, 2025. DOI 10.1038/s41598-025-91552-5 [P]
  11. Casile, A., Fregna, G., Boarini, V. et al. "Quantitative Comparison of Hand Kinematics Measured with a Markerless Commercial Head-Mounted Display and a Marker-Based Motion Capture System in Stroke Survivors." Sensors 23(18):7906, 2023. DOI 10.3390/s23187906 [P]
  12. Boulo, J., Blanchette, A. K., Cyr, A. and McFadyen, B. J. "Validity and reliability of the tracking measures extracted from the Oculus Quest 2 during locomotion." Computer Methods in Biomechanics and Biomedical Engineering: Imaging & Visualization 12(1), 2024. DOI 10.1080/21681163.2023.2274391 [P]
  13. Niehorster, D. C., Li, L. and Lappe, M. "The Accuracy and Precision of Position and Orientation Tracking in the HTC Vive Virtual Reality System for Scientific Research." i-Perception 8(3):2041669517708205, 2017. DOI 10.1177/2041669517708205 [P] — open access.
  14. Bauer, P., Lienhart, W. and Jost, S. "Accuracy Investigation of the Pose Determination of a VR System." Sensors 21(5):1622, 2021. DOI 10.3390/s21051622 [P] — note: frequently mis-cited under the non-existent title "Evaluation of the Accuracy of the HTC Vive".
  15. Sansone, L. G., Stanzani, R., Job, M., Battista, S., Signori, A. and Testa, M. "Robustness and static-positional accuracy of the SteamVR 1.0 virtual reality tracking system." Virtual Reality 26(3):903–924, 2022. DOI 10.1007/s10055-021-00584-5 [P]
  16. Kuhlmann de Canaviri, L. et al. "Static and Dynamic Accuracy and Occlusion Robustness of SteamVR Tracking 2.0 in Multi-Base Station Setups." Sensors 23(2):725, 2023. DOI 10.3390/s23020725 [P]
  17. Ware, C. and Balakrishnan, R. "Reaching for objects in VR displays: lag and frame rate." ACM Transactions on Computer-Human Interaction 1(4):331–356, 1994. DOI 10.1145/198425.198426 [P]
  18. MacKenzie, I. S. and Ware, C. "Lag as a determinant of human performance in interactive systems." Proceedings of INTERCHI '93, pp. 488–493. DOI 10.1145/169059.169431 [P]
  19. Kelkkanen, V., Lindero, D., Fiedler, M. and Zepernick, H.-J. "Hand-Controller Latency and Aiming Accuracy in 6-DOF VR." Advances in Human-Computer Interaction 2023:1563506, pp. 1–18. DOI 10.1155/2023/1563506 [P]
  20. Kuchenbecker, K. J., Fiene, J. and Niemeyer, G. "Improving contact realism through event-based haptic feedback." IEEE Transactions on Visualization and Computer Graphics 12(2):219–230, 2006. DOI 10.1109/TVCG.2006.32 [P]
  21. Okamura, A. M., Cutkosky, M. R. and Dennerlein, J. T. "Reality-based models for vibration feedback in virtual environments." IEEE/ASME Transactions on Mechatronics 6(3):245–252, 2001. DOI 10.1109/3516.951362 [P]
  22. Choi, S. and Kuchenbecker, K. J. "Vibrotactile Display: Perception, Technology, and Applications." Proceedings of the IEEE 101(9):2093–2104, 2013. DOI 10.1109/JPROC.2012.2221071 [P]
  23. Lopes, P., Ion, A. and Baudisch, P. "Impacto: Simulating Physical Impact by Combining Tactile Stimulation with Electrical Muscle Stimulation." Proceedings of UIST '15, pp. 11–19. DOI 10.1145/2807442.2807443 [P]
  24. Lécuyer, A. "Simulating Haptic Feedback Using Vision: A Survey of Research and Applications of Pseudo-Haptic Feedback." Presence: Teleoperators and Virtual Environments 18(1):39–53, 2009. DOI 10.1162/pres.18.1.39 [P]
  25. Samad, M., Gatti, E., Hermes, A., Benko, H. and Parise, C. "Pseudo-Haptic Weight: Changing the Perceived Weight of Virtual Objects By Manipulating Control-Display Ratio." Proceedings of CHI '19, Paper 320, pp. 1–13. DOI 10.1145/3290605.3300550 [P]
  26. Ujitoko, Y. and Ban, Y. "Survey of Pseudo-Haptics: Haptic Feedback Design and Application Proposals." IEEE Transactions on Haptics 14(4):699–711, 2021. DOI 10.1109/TOH.2021.3077619 [P]
  27. Kilteni, K., Groten, R. and Slater, M. "The Sense of Embodiment in Virtual Reality." Presence: Teleoperators and Virtual Environments 21(4):373–387, 2012. DOI 10.1162/PRES_a_00124 [P]
  28. Waltemate, T., Senna, I., Hülsmann, F., Rohde, M., Kopp, S., Ernst, M. O. and Botsch, M. "The impact of latency on perceptual judgments and motor performance in closed-loop interaction in virtual reality." Proceedings of VRST '16, pp. 27–35. DOI 10.1145/2993369.2993381 [P]
  29. Argelaguet, F., Hoyet, L., Trico, M. and Lécuyer, A. "The role of interaction in virtual embodiment: Effects of the virtual hand representation." IEEE Virtual Reality 2016, pp. 3–10. DOI 10.1109/VR.2016.7504682 [P]
  30. Weser, V. and Proffitt, D. R. "Expertise in Tool Use Promotes Tool Embodiment." Topics in Cognitive Science 13(4):597–609, 2021. DOI 10.1111/tops.12538 [P]
  31. Richlan, F., Weiß, M., Kastner, P. and Braid, J. "Virtual training, real effects: a narrative review on sports performance enhancement through interventions in virtual reality." Frontiers in Psychology 14:1240790, 2023. DOI 10.3389/fpsyg.2023.1240790 [P]
  32. Neumann, D. L., Moffitt, R. L., Thomas, P. R., Loveday, K., Watling, D. P., Lombard, C. L., Antonova, S. and Tremeer, M. A. "A systematic review of the application of interactive virtual reality to sport." Virtual Reality 22(3):183–198, 2018. DOI 10.1007/s10055-017-0320-5 [P]
  33. Miles, H. C., Pop, S. R., Watt, S. J., Lawrence, G. P. and John, N. W. "A review of virtual environments for training in ball sports." Computers & Graphics 36(6):714–726, 2012. DOI 10.1016/j.cag.2012.04.007 [P] — bibliographic details verified; the perceptual-versus-functional-fidelity wording quoted in §6.6 comes from a search excerpt of the abstract and should be checked against the PDF before being quoted verbatim.
  34. Gray, R. "Transfer of Training from Virtual to Real Baseball Batting." Frontiers in Psychology 8:2183, 2017. DOI 10.3389/fpsyg.2017.02183 [P]
  35. Michalski, S. C., Szpak, A., Saredakis, D., Ross, T. J., Billinghurst, M. and Loetscher, T. "Getting your game on: Using virtual reality to improve real table tennis skills." PLoS ONE 14(9):e0222351, 2019. DOI 10.1371/journal.pone.0222351 [P]
  36. Oagaz, H., Schoun, B. and Choi, M.-H. "Performance Improvement and Skill Transfer in Table Tennis Through Training in Virtual Reality." IEEE Transactions on Visualization and Computer Graphics 28(12):4332–4343, 2022. DOI 10.1109/TVCG.2021.3086403 [P]
  37. Wu, E., Piekenbrock, M., Nakumura, T. and Koike, H. "SPinPong — Virtual Reality Table Tennis Skill Acquisition using Visual, Haptic and Temporal Cues." IEEE Transactions on Visualization and Computer Graphics 27(5):2566–2576, 2021. DOI 10.1109/TVCG.2021.3067761 [P]
  38. Harris, D. J., Buckingham, G., Wilson, M. R., Brookes, J., Mushtaq, F., Mon-Williams, M. and Vine, S. J. "The effect of a virtual reality environment on gaze behaviour and motor skill learning." Psychology of Sport and Exercise 50:101721, 2020. DOI 10.1016/j.psychsport.2020.101721 [P]
  39. Harris, D. J., Buckingham, G., Wilson, M. R., Brookes, J., Mushtaq, F., Mon-Williams, M. and Vine, S. J. "Exploring sensorimotor performance and user experience within a virtual reality golf putting simulator." Virtual Reality 25(3):647–654, 2021. DOI 10.1007/s10055-020-00480-4 [P] — note: "Testing the fidelity and validity of a virtual reality golf putting simulator" is the OSF preprint title of this same work (10.31234/osf.io/j2txe), not a separate paper.
  40. Uchiyama, H. and Saito, H. "AR Supporting System for Pool Games Using a Camera-Mounted Handheld Display." Advances in Human-Computer Interaction 2008:357270, pp. 1–13. DOI 10.1155/2008/357270 [P]
  41. Sousa, L., Alves, R. N. and Rodrigues, J. M. F. "Augmented reality system to assist inexperienced pool players." Computational Visual Media 2(2):183–193, 2016. DOI 10.1007/s41095-016-0047-3 [P]
  42. Wu, F. and Dellinger, A. "Capturing Reality for a Billiards Simulation." In Augmented Reality, Virtual Reality, and Computer Graphics (LNCS), pp. 289–298. Springer, 2017. DOI 10.1007/978-3-319-60922-5_23 [P] — note: my two research passes disagreed on the container, one giving Augmented Reality, Virtual Reality, and Computer Graphics (AVR 2017) and the other Entertainment Computing – ICEC 2017. The ISBN embedded in the DOI matches the AVR volume, so that is the version listed here. The abstract was not verified by either pass.

Cue sports in VR, AR and haptics

  1. Haar, S., Sundar, G. and Faisal, A. A. "Embodied virtual reality for the study of real-world motor learning." PLOS ONE 16(1):e0245717, 2021. DOI 10.1371/journal.pone.0245717 [P] — open access.
  2. Haar, S., van Assel, C. M. and Faisal, A. A. "Motor learning in real-world pool billiards." Scientific Reports 10(1), 2020. DOI 10.1038/s41598-020-76805-9 [P] — preprint bioRxiv 10.1101/612218.
  3. Gourishankar, V., Srimathveeravalli, G. and Kesavadas, T. "HapStick: A High Fidelity Haptic Simulation for Billiards." World Haptics 2007 (Second Joint EuroHaptics Conference and Symposium on Haptic Interfaces for Virtual Environment and Teleoperator Systems), pp. 494–500. IEEE. DOI 10.1109/WHC.2007.63 [P]
  4. De Paolis, L. T., Aloisio, G. and Pulimeno, M. "A 3D Simulation of a Game of Billiards Using a Haptic Device." GRAPP 2008, pp. 450–455. SciTePress. DOI 10.5220/0001097804500455 [P] — implemented in XVR with rigid-body dynamics via the ODE library.
  5. Thai, E. and Kumar, A. R. "How Haptic Feedback in a Mixed Reality Pool Game Affects Real-Life Pool Performance." Proceedings of the Human Factors and Ergonomics Society Annual Meeting 63(1):2323–2327, 2019. DOI 10.1177/1071181319631294 [P]
  6. De Grandpré, A., Giroux, F., Lasbareilles, C., Boasen, J., Aumais, A., Lesage, A., Courtemanche, F., Stagg, C., Sénécal, S. and Léger, P.-M. "Identifying Neural Correlates of Motor Learning in a Naturalistic VR-Based Motor Task." In Information Systems and Neuroscience (LNISO, NeuroIS Retreat 2024), pp. 179–185. Springer, 2025. DOI 10.1007/978-3-031-71385-9_14 [P] — paywalled; whether the pool implementation was a commercial title or a custom build is unconfirmed.
  7. Yan, J., Zhan, Y. and Yang, Z. "A Billiards Learning Assistant System with Head-Mounted AR." 2025 11th International Conference on Virtual Reality (ICVR), pp. 36–41. IEEE. DOI 10.1109/ICVR66534.2025.11172454 [P]

Robotic and computational billiards

  1. Greenspan, M., Lam, J., Godard, M., Zaidi, I., Jordan, S., Leckie, W., Anderson, K. and Dupuis, D. "Toward a Competitive Pool-Playing Robot." Computer 41(1):46–53, 2008. DOI 10.1109/MC.2008.33 [P]
  2. Long, F., Herland, J., Tessier, M.-C., Naulls, D., Roth, A., Roth, G. and Greenspan, M. "Robotic pool: an experiment in automatic potting." 2004 IEEE/RSJ IROS, vol. 3, pp. 2520–2525. DOI 10.1109/IROS.2004.1389787 [P] — note: the IEEE/Crossref record renders the second author as "J. Berland"; the paper itself and secondary sources give Johan Herland. Verify against the PDF.
  3. Greenspan, M., Lam, J., Leckie, W., Godard, M., Zaidi, I., Anderson, K., Dupuis, D. and Jordan, S. "Toward a Competitive Pool Playing Robot: Is Computational Intelligence Needed to Play Robotic Pool?" 2007 IEEE Symposium on Computational Intelligence and Games (CIG), pp. 380–388. DOI 10.1109/CIG.2007.368124 [P]
  4. Lam, J. and Greenspan, M. "Eye-In-Hand Visual Servoing for Accurate Shooting in Pool Robotics." 2008 Canadian Conference on Computer and Robot Vision (CRV), pp. 11–17. DOI 10.1109/CRV.2008.30 [P]
  5. Greenspan, M. Method and apparatus for positional error correction in a robotic pool system using a cue-aligned local camera. US Patent 7,831,337 B2, filed 23 September 2005, granted 9 November 2010. [C]
  6. Leckie, W. and Greenspan, M. "Monte-Carlo Methods in Pool Strategy Game Trees." In Computers and Games (LNCS 4630), pp. 244–255. Springer, 2007. DOI 10.1007/978-3-540-75538-8_22 [P]
  7. Archibald, C., Altman, A. and Shoham, Y. "Analysis of a Winning Computational Billiards Player." Proceedings of IJCAI-09, pp. 1377–1382. [P] https://www.ijcai.org/Proceedings/09/Papers/231.pdf
  8. Archibald, C., Altman, A., Greenspan, M. and Shoham, Y. "Computational Pool: A New Challenge for Game Theory Pragmatics." AI Magazine 31(4):33–41, 2010. DOI 10.1609/aimag.v31i4.2312 [P] — open access; the source for the tournament rules, the five-parameter shot representation and the noise model.
  9. Archibald, C., Altman, A. and Shoham, Y. "A Distributed Agent for Computational Pool." IEEE Transactions on Computational Intelligence and AI in Games 8(2):190–202, 2016. DOI 10.1109/TCIAIG.2016.2549748 [P]
  10. Smith, M. "PickPocket: A computer billiards shark." Artificial Intelligence 171(16–17):1069–1091, 2007. DOI 10.1016/j.artint.2007.04.011 [P]
  11. Smith, M. "Running the Table: An AI for Computer Billiards." Proceedings of AAAI-06, pp. 994–999. AAAI Press. [P] https://cdn.aaai.org/AAAI/2006/AAAI06-156.pdf
  12. Landry, J.-F. and Dussault, J.-P. "AI Optimization of a Billiard Player." Journal of Intelligent and Robotic Systems 50(4):399–417, 2007. DOI 10.1007/s10846-007-9172-7 [P]
  13. Chua, S. C., Wong, E. K. and Koo, V. C. "Intelligent Pool Decision System Using Zero-Order Sugeno Fuzzy System." Journal of Intelligent and Robotic Systems 44(2):161–186, 2005. DOI 10.1007/s10846-005-9009-1 [P] — bibliographic record solid; abstract not retrievable, so read before characterising its content.
  14. Chen, Y. and Li, Y. "Macro and Micro Reinforcement Learning for Playing Nine-ball Pool." 2019 IEEE Conference on Games (CoG), pp. 1–4. DOI 10.1109/CIG.2019.8848113 [P]
  15. Tung, K. G., Wang, S. W., Tai, W. K., Way, D. L. and Chang, C. C. "Toward Human-like Billiard AI Bot Based on Backward Induction and Machine Learning." 2019 IEEE SSCI, pp. 924–932. DOI 10.1109/SSCI44817.2019.9003085 [P]
  16. Fragkiadaki, K., Agrawal, P., Levine, S. and Malik, J. "Learning Visual Predictive Models of Physics for Playing Billiards." ICLR 2016 (poster). arXiv:1511.07404. [R/P] — the arXiv record carries no journal reference; the ICLR attribution comes from DBLP.
  17. Memery, S., Denamganaï, K., Zhang, J., Tu, Z., Guo, Y. and Subr, K. "CueTip: An Interactive and Explainable Physics-aware Pool Assistant." SIGGRAPH '25 Conference Papers, pp. 1–11. ACM, 2025. DOI 10.1145/3721238.3730742 [P] — preprint arXiv:2501.18291. Built on pooltool [44].
  18. Sang, W. C. S. (William Cheung Shu Sang). Automating skills using a robot snooker player. PhD thesis, University of Bristol, 1994. [T] — note: major secondary sources garble this name differently ("Chang, S. W. S."; "Sang, W. C. S."). Bristol's own repository record gives William Cheung Shu Sang.
  19. Ho, K. H. L., Martin, T. and Baldwin, J. "Snooker Robot Player — 20 Years on." 2007 IEEE CIG, pp. 1–8. DOI 10.1109/CIG.2007.368072 [P]
  20. Nierhoff, T., Heunisch, K. and Hirche, S. "Strategic play for a pool-playing robot." 2012 IEEE ARSO, pp. 72–78. DOI 10.1109/ARSO.2012.6213402 [P]
  21. Denman, H., Rea, N. and Kokaram, A. "Content-based analysis for video from snooker broadcasts." Computer Vision and Image Understanding 92(2–3):176–195, 2003. DOI 10.1016/j.cviu.2003.06.005 [P]
  22. Rodriguez-Lozano, F. J., Gámez-Granados, J. C., Martínez, H., Palomares, J. M. and Olivares, J. "3D reconstruction system and multiobject local tracking algorithm designed for billiards." Applied Intelligence 53(19):21543–21575, 2023. DOI 10.1007/s10489-023-04542-3 [P]
  23. Greenspan, M. "UofA Wins the Pool Tournament." ICGA Journal 28(3):191–193, 2005. DOI 10.3233/ICG-2005-28317 [P]
  24. Greenspan, M. "Pickpocket Wins Pool Tournament." ICGA Journal 29(3):153–156, 2006. DOI 10.3233/ICG-2006-29309 [P]

Commercial products (vendor material)

  1. Chaplin, S. Interview on the origins of Celeris and Virtual Pool. povpool.com, 8 August 2012. [C] — the source for the defence/aerospace-simulation provenance.
  2. Celeris, Inc. Virtual Pool 4 product and store pages. [V]
  3. Cherry Pop Games. Snooker Nation Championship Steam store page. [V] — the source of the "utilising the WSC Real championship physics engine" statement.

Open-source implementations

  1. Papavasiliou, D. Billiards. GPL; built on the Techne framework, scripted in Lua 5.1. [S] https://www.nongnu.org/billiards/
  2. Foobillard++. GPL; enhanced fork of Berger's foobillard 3.0a. [S] https://foobillardplus.sourceforge.net/
  3. Alciatore, D. "Pool/Billiards Simulators." [C] https://drdavepoolinfo.com/faq/physics/simulator/ — expert-practitioner assessment, offered without measurement data.

Additional cue and cushion physics

  1. Cohen, G. L. "Three cushion billiards: notes on the diamond system." Sports Engineering 5(1):43–51, 2002. DOI 10.1046/j.1460-2687.2002.00095.x [P]
  2. Cross, R. "Energy loss in cue-ball collisions." European Journal of Physics 42(6):065003, 2021. DOI 10.1088/1361-6404/ac1e7c [P]
  3. Cross, R. "Impact of a cue with a billiard ball." Proceedings of the Institution of Mechanical Engineers, Part P: Journal of Sports Engineering and Technology 239(4):647–651, 2023. DOI 10.1177/17543371231184011 [P]
  4. Shimamura, S., Suga, K., Ezawa, Y. and Aoki. "Effects of Material Properties of Cue on Ball Trajectory in Billiards." Journal of Solid Mechanics and Materials Engineering 3(7):978–989, 2009. JSME. DOI 10.1299/jmmp.3.978 [P]

Rigid-body contact and friction solvers

  1. Bender, J., Erleben, K. and Trinkle, J. "Interactive Simulation of Rigid Body Dynamics in Computer Graphics." Computer Graphics Forum 33(1):246–270, 2014. DOI 10.1111/cgf.12272 [P] — the Eurographics 2012 STAR preprint lists a fourth author, Erwin Coumans; Crossref's CGF record lists three. Cite whichever version you use.
  2. Lengyel, E. "A Jitter-Tolerant Rigid Body Sleep Condition." In Game Engine Gems 2, ed. E. Lengyel, A K Peters / CRC Press, 2011, ch. 27. DOI 10.1201/b11333-27 [B] — text not obtained; page numbers disagree between Crossref (395–398) and the Game Gems database (379–381). Do not attribute a specific method to it.
  3. Millington, I. cyclone-physics (source accompanying Game Physics Engine Development). [S] https://github.com/idmillington/cyclone-physics — the sleep condition is in src/body.cpp; note the header comments give a default sleep epsilon of 0.1 while src/core.cpp sets 0.3.
  4. Box2D v3 source, src/solver.c and include/box2d/types.h. [S] https://box2d.org
  5. NVIDIA PhysX, PxRigidDynamic.h. [S] https://github.com/NVIDIA-Omniverse/PhysX
  6. Coumans, E. Bullet 2.83 Physics SDK Manual, 2015. [C] https://github.com/bulletphysics/bullet3/raw/master/docs/Bullet_User_Manual.pdf — states that Bullet "uses its btSequentialImpulseConstraintSolver by default", and credits "Erin Catto, Blizzard: accumulated impulse in sequential impulse". Contains no documentation of sleeping or deactivation.
  7. Bullet Physics developer forum threads, pybullet.org/Bullet/phpBB3. [C] — cited for: Coumans on island merging under an over-large world AABB; Gregorius' "pseudo velocities and split impulses are the same" and Coumans on split impulse (viewtopic.php?t=3795); Catto and Gregorius on rolling-resistance design (viewtopic.php?t=1896); and an unresolved 2014 report of spheres that never stop (viewtopic.php?f=9&t=10150). Developer forum posts, not publications.
  8. Bullet examples/RollingFrictionDemo/RollingFrictionDemo.cpp. [S] — "Generally it is best to leave the rolling friction coefficient zero (or close to zero)."
  9. Bullet Physics issue tracker. [S] https://github.com/bulletphysics/bullet3 — PR #2138 ("Implement 'cone friction' for the rolling friction, to avoid curved trajectories", merged 2019-03-04, fixing issue #2117) and issue #4188 ("Spinning friction only applied if rolling friction > 0", opened 2022, open).
  10. Ai, J., Chen, J.-F., Rotter, J. M. and Ooi, J. Y. "Assessment of rolling resistance models in discrete element simulations." Powder Technology 206(3):269–282, 2011. DOI 10.1016/j.powtec.2010.09.030 [P] — abstract verified; body not read, so its model taxonomy is not quoted here.
  11. Iwashita, K. and Oda, M. "Rolling Resistance at Contacts in Simulation of Shear Band Development by DEM." Journal of Engineering Mechanics 124(3):285–292, 1998. DOI 10.1061/(ASCE)0733-9399(1998)124:3(285) [P]
  12. Wensrich, C. M. and Katterfeld, A. "Rolling friction as a technique for modelling particle shape in DEM." Powder Technology 217:409–417, 2012. DOI 10.1016/j.powtec.2011.10.057 [P]
  13. Kuhn, M. R. "Transient rolling friction model for discrete element simulations of sphere assemblies." Comptes Rendus Mécanique 342(3):129–140, 2014. DOI 10.1016/j.crme.2013.03.002 [P] — preprint arXiv:1812.10391.
  14. Itasca International. "Rolling Resistance Linear Model" (PFC documentation). [C] https://www.itascainternational.com/software/rolling-resistance-linear-model-in-pfc — commercial software documentation; the clearest short statement that the limiting moment is normal force × coefficient × effective contact radius.
  15. Catto, E. Publications and GDC talks. [C] https://box2d.org/publications/ — cited here: "Iterative Dynamics with Temporal Coherence", GDC 2005 (a talk plus a self-published ~20-page technical article dated 5 June 2005; no DOI, not peer-reviewed); "Fast and Simple Physics using Sequential Impulses", GDC 2006; "Modeling and Solving Constraints", GDC 2009; "Soft Constraints", GDC 2011.
  16. Baumgarte, J. "Stabilization of constraints and integrals of motion in dynamical systems." Computer Methods in Applied Mechanics and Engineering 1(1):1–16, 1972. DOI 10.1016/0045-7825(72)90018-7 [P] — citation verified via Crossref; article text not read.
  17. Baraff, D. "Analytical methods for dynamic simulation of non-penetrating rigid bodies." ACM SIGGRAPH Computer Graphics 23(3):223–232, 1989. DOI 10.1145/74333.74356 [P] — full text read: https://www.cs.cmu.edu/~baraff/papers/sig89.pdf
  18. Baraff, D. "Coping with friction for non-penetrating rigid body simulation." ACM SIGGRAPH Computer Graphics 25(4):31–41, 1991. DOI 10.1145/122718.122722 [P] — full text read: https://www.cs.cmu.edu/~baraff/papers/sig91.pdf
  19. Baraff, D. "Fast contact force computation for nonpenetrating rigid bodies." Computer Graphics Proceedings, Annual Conference Series (SIGGRAPH '94), pp. 23–34. DOI 10.1145/192161.192168 [P] — full text read: https://www.cs.cmu.edu/~baraff/papers/sig94.pdf
  20. Baraff, D. Dynamic Simulation of Non-Penetrating Rigid Bodies. PhD thesis, Cornell University, Technical Report TR 92-1275, March 1992. [T] https://hdl.handle.net/1813/7115
  21. Stewart, D. E. and Trinkle, J. C. "An implicit time-stepping scheme for rigid body dynamics with inelastic collisions and Coulomb friction." International Journal for Numerical Methods in Engineering 39(15):2673–2691, 1996. DOI 10.1002/(SICI)1097-0207(19960815)39:15<2673::AID-NME972>3.0.CO;2-I [P] — full text not obtained; the scheme as described here is taken from [169] and from Stewart and Trinkle's ICRA 2000 companion paper.
  22. Anitescu, M. and Potra, F. A. "Formulating Dynamic Multi-Rigid-Body Contact Problems with Friction as Solvable Linear Complementarity Problems." Nonlinear Dynamics 14(3):231–247, 1997. DOI 10.1023/A:1008292328909 [P] — full text and abstract not obtained; their contribution as described here is quoted from Stewart and Trinkle's ICRA 2000 paper.
  23. Mirtich, B. and Canny, J. "Impulse-based simulation of rigid bodies." Proceedings of the 1995 Symposium on Interactive 3D Graphics (I3D '95), pp. 181–188, 217. DOI 10.1145/199404.199436 [P]. See also Mirtich, B. Impulse-based Dynamic Simulation of Rigid Body Systems, PhD thesis, UC Berkeley, 1996 [T] (ACM Guide identifier 10.5555/924581 — not a DOI). Neither full text obtained.
  24. Tonge, R., Benevolenski, F. and Voroshilov, A. "Mass splitting for jitter-free parallel rigid body simulation." ACM Transactions on Graphics 31(4), 2012. DOI 10.1145/2185520.2185601 [P]
  25. Macklin, M., Storey, K., Lu, M., Terdiman, P., Chentanez, N., Jeschke, S. and Müller, M. "Small steps in physics simulation." Proceedings of the 18th ACM SIGGRAPH/Eurographics Symposium on Computer Animation (SCA 2019), pp. 1–7. DOI 10.1145/3309486.3340247 [P]
  26. Macklin, M., Müller, M. and Chentanez, N. "XPBD: Position-Based Simulation of Compliant Constrained Dynamics." Proceedings of the 9th International Conference on Motion in Games (MIG 2016), pp. 49–54. DOI 10.1145/2994258.2994272 [P] — Crossref truncates the title to "XPBD"; the subtitle is from the PDF.
  27. Müller, M., Macklin, M., Chentanez, N., Jeschke, S. and Kim, T.-Y. "Detailed Rigid Body Simulation with Extended Position Based Dynamics." Computer Graphics Forum 39(8):101–112, 2020. DOI 10.1111/cgf.14105 [P]
  28. Erleben, K. "Velocity-based shock propagation for multibody dynamics animation." ACM Transactions on Graphics 26(2):12, 2007. DOI 10.1145/1243980.1243986 [P]
  29. Todorov, E. "Convex and analytically-invertible dynamics with contacts and constraints: Theory and implementation in MuJoCo." 2014 IEEE International Conference on Robotics and Automation (ICRA), pp. 6054–6061. DOI 10.1109/ICRA.2014.6907751 [P]
  30. Lankarani, H. M. and Nikravesh, P. E. "A Contact Force Model With Hysteresis Damping for Impact Analysis of Multibody Systems." Journal of Mechanical Design 112(3):369–376, 1990. DOI 10.1115/1.2912617 [P] — earlier conference version: 15th Design Automation Conference, 1989, DOI 10.1115/DETC1989-0104.
  31. Acary, V. and Brogliato, B. Numerical Methods for Nonsmooth Dynamical Systems: Applications in Mechanics and Electronics. Lecture Notes in Applied and Computational Mechanics vol. 35, Springer Berlin Heidelberg, 2008. DOI 10.1007/978-3-540-75392-6. ISBN 978-3-540-75391-9 / 978-3-540-75392-6. 525 pp. [B] — §13.3.7 is the standard citation for pyramidal anisotropy. The volume number comes from the Siconos bibliography, not from Crossref.
  32. Baraff, D. "Issues in computing contact forces for non-penetrating rigid bodies." Algorithmica 10(2–4):292–352, 1993. DOI 10.1007/BF01891843 [P] — the peer-reviewed journal version of the complexity results; [152], [153] and [154] are all conference papers.
  33. Witkin, A. and Baraff, D. "Physically Based Modeling: Principles and Practice." SIGGRAPH '97 Course Notes, 1997. [C] https://www.cs.cmu.edu/~baraff/sigcourse/ — course notes, not peer-reviewed, but canonical; notesd2.pdf gives the clearest statement of the colliding-versus-resting contact split.
  34. Stewart, D. E. "Rigid-Body Dynamics with Friction and Impact." SIAM Review 42(1):3–39, 2000. DOI 10.1137/S0036144599360110 [P]
  35. Champneys, A. R. and Várkonyi, P. L. "The Painlevé paradox in contact mechanics." IMA Journal of Applied Mathematics 81(3):538–588, 2016. DOI 10.1093/imamat/hxw027 [P] — preprint arXiv:1601.03545.
  36. Painlevé, P. "Sur les lois du frottement de glissement." Comptes Rendus des Séances de l'Académie des Sciences 121:112–115, 1895; follow-ups 141:401–405 and 141:546–552, 1905. [P]
  37. Stewart, D. E. "Convergence of a time-stepping scheme for rigid-body dynamics and resolution of Painlevé's problem." Archive for Rational Mechanics and Analysis 145:215–260, 1998. DOI 10.1007/s002050050129 [P] — note the DOI ends 129; ...128 resolves to an unrelated paper.
  38. Pang, J.-S. and Trinkle, J. C. "Complementarity formulations and existence of solutions of dynamic multi-rigid-body contact problems with Coulomb friction." Mathematical Programming 73(2):199–226, 1996. DOI 10.1007/BF02592103 [P] — not read. See also Pang and Trinkle, ZAMM 80(10):643–663, 2000.
  39. Anitescu, M. "A fixed time-step approach for multibody dynamics with contact and friction." IEEE/RSJ IROS 2003, pp. 3725–3731. DOI 10.1109/IROS.2003.1249734 [P] — open access: https://www.mcs.anl.gov/papers/P1034.pdf
  40. Guendelman, E., Bridson, R. and Fedkiw, R. "Nonconvex rigid bodies with stacking." ACM Transactions on Graphics 22(3):871–878, 2003. DOI 10.1145/882262.882358 [P] — the source of the third-party critique of microcollision models.
  41. Coumans, E. "Exploring MLCP solvers and Featherstone." Game Developer Conference, 2014. [C] https://media.gdcvault.com/GDC2014/Presentations/Coumans_Erwin_Physics_for_Game.pdf
  42. Catto, E. "Solver2D." box2d.org, 5 February 2024. [C] https://box2d.org/posts/2024/02/solver2d/ — implements and compares eight solvers on common benchmarks; the source of Catto's own account of having "reframed PGS as Sequential Impulses".
  43. Le Lidec, Q., Jallet, W., Montaut, L., Laptev, I., Schmid, C. and Carpentier, J. "Contact Models in Robotics: a Comparative Analysis." arXiv:2304.06372v3, 2024. [R/P] — also reported to appear in IEEE Transactions on Robotics, which I did not verify.
  44. Preclik, T. Frictional Rigid Body Dynamics. Studienarbeit, Lehrstuhl für Informatik 10, FAU Erlangen-Nürnberg, 2007. [T] https://www10.cs.fau.de/publications/theses/2007/Preclik_SA_2007.pdf — a student thesis, not peer-reviewed; §3.3.2 contains the 19-sphere anisotropy experiment quoted in §5.8.
  45. Trinkle, J. C., Pang, J.-S., Sudarsky, S. and Lo, G. "On Dynamic Multi-Rigid-Body Contact Problems with Coulomb Friction." ZAMM 77(4):267–279, 1997. DOI 10.1002/zamm.19970770411 [P]
  46. Bonnefon, O. and Daviet, G. "Quartic formulation of Coulomb 3D frictional contact." INRIA Technical Report RT-0400, 2011. [R] HAL id inria-00553859. — record and abstract verified through the HAL search API; the report itself was not read (HAL bot-check).
  47. Daviet, G., Bertails-Descoubes, F. and Boissieux, L. "A hybrid iterative solver for robustly capturing Coulomb friction in hair dynamics." ACM Transactions on Graphics 30(6), Article 139, 2011. DOI 10.1145/2070781.2024173 [P]
  48. Bertails-Descoubes, F., Cadoux, F., Daviet, G. and Acary, V. "A nonsmooth Newton solver for capturing exact Coulomb friction in fiber assemblies." ACM Transactions on Graphics 30(1), Article 6, 2011. DOI 10.1145/1899404.1899410 [P]
  49. Alart, P. and Curnier, A. "A mixed formulation for frictional contact problems prone to Newton like solution methods." Computer Methods in Applied Mechanics and Engineering 92(3):353–375, 1991. DOI 10.1016/0045-7825(91)90022-X [P]
  50. Tasora, A. and Anitescu, M. "A Fast NCP Solver for Large Rigid-Body Problems with Contacts, Friction, and Joints." [C/P] https://www.projectchrono.org/tasora/pubblicazioni/tasora-2008-springer.pdf — the source of the closed-form non-expansive cone projection in §5.8.
  51. Moreau, J. J. "Unilateral Contact and Dry Friction in Finite Freedom Dynamics." In Nonsmooth Mechanics and Applications, CISM Courses and Lectures No. 302, Springer Vienna, 1988, pp. 1–82. DOI 10.1007/978-3-7091-2624-0_1 [B] — the CISM series and volume number are not carried by Crossref; verify against the physical volume.
  52. Moreau, J. J. "Numerical aspects of the sweeping process." Computer Methods in Applied Mechanics and Engineering 177(3–4):329–349, 1999. DOI 10.1016/S0045-7825(98)00387-9 [P]
  53. Jean, M. "The non-smooth contact dynamics method." Computer Methods in Applied Mechanics and Engineering 177(3–4):235–257, 1999. DOI 10.1016/S0045-7825(98)00383-1 [P] — [187], [188] and Anitescu, Potra and Stewart, CMAME 177(3–4):183–197 (DOI 10.1016/S0045-7825(98)00380-6) are in the same special issue and can be cited as a unit.
  54. Acary, V., Brémond, M. and Huber, O. "On solving frictional contact problems: formulations and comparisons of numerical methods." In Advanced Topics in Nonsmooth Dynamics, Springer, 2018, pp. 375–457. DOI 10.1007/978-3-319-75972-2_10 [P] — concludes that "there is no universal solver."
  55. Kaufman, D. M., Sueda, S., James, D. L. and Pai, D. K. "Staggered projections for frictional contact in multibody systems." ACM SIGGRAPH Asia 2008. DOI 10.1145/1457515.1409117 [P] — see also Kaufman, Edmunds and Pai, "Fast frictional dynamics for rigid bodies", SIGGRAPH 2005, pp. 946–956, DOI 10.1145/1186822.1073295.
  56. Smith, R. L. (maintainer). Open Dynamics Engine Manual. [C] https://ode.org/wiki/index.php?title=Manual — the source of the ERP and CFM formulas discussed in §5.7.

Between the two halves — what this engine does not use

The review above is deliberately wider than the implementation below. This is the join: everything in the literature that the engine has not taken up, and why.

A survey that only covered what was implemented would flatter the engine and teach a reader less. The list below is the honest difference, and it is where the next work is.

From the literatureStatus hereWhy, and what it would cost
Compliant / deformable cushion. Penalty contact with a Hertz normal force and Hunt–Crossley damping, as used for pool by Gismeros Moreno et al. (2021). Not used. The cushion here is rigid, with the impact integrated over its own accumulated normal impulse. That is the Mathavan–Jackson–Parkin scheme, and it is better than a reflection — but it assumes the rubber does not deform, and those authors give 2.5 m/s of normal velocity as the limit of that assumption. Every hard shot in this game exceeds it, and the engine's own source labels its behaviour above that speed as extrapolation. A lumped spring-damper integrated over the real contact duration is affordable — contacts are rare and involve one ball — but the stiffness and damping constants for a billiards cushion have never been published, so it would need fitting against the same high-speed measurements.
Finite-element or hyperelastic modelling of the cushion profile. Does not exist to use. Searched for specifically. Table-tennis rubber, golf balls and tennis balls all have such studies; a billiards cushion profile appears to have none. This is a gap in the field rather than a gap in the engine.
Event-driven simulation. Solving in closed form for the next event rather than stepping time. Not used. A deliberate choice, not an oversight. This engine steps at a fixed 2 kHz because it must be bit-identical on two headsets playing lockstep, and because it carries contacts an event formulation does not close over — a ball on a curved cloth lip, a ball in a net, skittles. The event approach is more accurate per collision and less robust when many contacts coincide.
Sleeping criteria from the rigid-body literature. Used, but the literature has little to offer. The review's finding is worth repeating: sleeping is almost absent from the peer-reviewed work, and where it appears it is treated as a defect to test for. For cue sports the problem dissolves — the rolling-to-stationary time is v₀ / (μr g) in closed form. The sleep rule here exists for the balls in the troughs under the table, which are solved as general rigid bodies and therefore inherit the general problem.
Differentiable billiards. Gradients through the simulation for learning or control. Not used. Nothing in the game asks for gradients; the opponent searches by sampling simulated shots. Noted because it is where the academic interest currently is.
Published validation of pocket capture and rattling. Nothing to use. The review finds this thin. The pocket model here — three distinct circles, a cloth cut as a signed distance field, and a lip a ball rides down — is the engine's own, tuned against play rather than against measurements, because there are no measurements to tune against.
Ball–ball friction coefficients. Used, with the spread the literature reports. Throw is emergent here rather than fitted, which is the right shape; but the coefficient it depends on is one of the least well-pinned numbers in the field.

Part II — This engine

The models, the mathematics and the algorithms, as implemented.

Part II contents

A reference for the "system description" chapters of a paper. Everything below is read off the source; file:line citations are given for every non-trivial claim, and code comments are quoted where they record a measurement, an experiment or a bug that motivated a choice. Where the source does not settle a question this document says so rather than guessing.

Source files described:

File Role
mote/games/thumbycue/src/cue_physics.h data model (CueWorld, CueBall, CueSeg)
mote/games/thumbycue/src/cue_physics.c ball motion, ball–ball, cushions, jaws, pockets, the drop
mote/games/thumbycue/src/cue_table.c table geometry: beds, cushion chains, jaw curves, pocket cuts
mote/games/thumbycue/src/cue_trig.h deterministic sin/cos
mote/engine/physics/mote_phys.c general rigid-body solver (skittles, everything under the cloth)
CueVR/src/cuevr_cue.c VR cue construction, pose ring, contact detection, stroke measurement
CueVR/src/cuevr_hit.c segment–sphere contact and strike geometry
CueVR/src/cuevr_app.c strike → physics hand-off, tip/ball momentum transfer, jump launch
mote/platform/xr/mote_xr.c, mote_xr.h 500 Hz pose sampling thread, XrSpaceVelocity
mote/games/thumbycue/src/cue_ai.c opponent shot search (appendix)

0. Symbol table

Ball state and cloth

Symbol Code Meaning Value / source
x CueBall.pos ball centre, world metres; table plane is world x–z, y up, cloth at y=0 cue_physics.h:68
v CueBall.vel linear velocity (m/s) cue_physics.h:69
ω CueBall.w angular velocity (rad/s), world frame, full 3-D cue_physics.h:70
Q CueBall.orient render orientation, a 3×3 matrix integrated from ω cue_physics.h:71
R CueWorld.R, CueBall.r ball radius; per-ball r>0 overrides (English pool: 47.6 mm cue ball vs 50.8 mm objects) cue_physics.h:110, :623
m CueWorld.mass, CueBall.m ball mass; per-ball override as above cue_physics.h:111, :626
I — I=25mR2, uniform solid sphere cue_physics.c:499, :444, :661
g CueWorld.g 9.806 m/s² cue_physics.c:47
rc rc centre→cloth-contact vector, (0,−R,0) cue_physics.c:488
u u contact-point slip, u=v+ω×rc, horizontal part only cue_physics.c:490–492
μs mu_s ball–cloth kinetic (sliding) friction 0.20 default, cue_physics.c:53
μr mu_r rolling resistance 0.010 default, cue_physics.c:54; per-table override cue_table.c:2899
αspin spin_decel vertical-spin angular deceleration, =5μspg/(2R) with μsp=0.022 cue_physics.c:57
h CUE_H, g_sub_h integrator substep, 1/2000 s cue_physics.c:18, :2568
Vstop V_STOP 0.005 m/s linear rest threshold cue_physics.c:33
Wstop W_STOP 0.05 rad/s spin rest threshold cue_physics.c:35

Collisions

Symbol Code Meaning Value / source
ebb e_bb ball–ball restitution 0.96, cue_physics.c:58
μbb mu_bb ball–ball friction (throw) 0.06, cue_physics.c:59
e0 e_cush cushion restitution at zero approach speed per table, 0.930–0.990, cue_table.c:76–108
ke cush_efall fall of e per m/s of approach 0.038–0.062 per table, same
emin e_cush_min floor on cushion restitution 0.55, cue_table.c:108 ("Marlow's rails, as the floor")
μw mu_cush ball–cushion friction 0.12, cue_physics.c:63
κ cush_spin fraction of the rail friction impulse that becomes new vertical spin 0.30, cue_physics.c:64
S,C cush_sin, cush_cos sin⁡θ, cos⁡θ of the contact-normal tilt; stored as sine/cosine, never as an angle cue_physics.h:196–203, cue_table.c:2843–2846
ebed e_bed slate/cloth restitution for a landing ball 0.40, cue_physics.c:75
vland v_land below this downward speed a landing settles flat (~1 mm of rise) 0.14 m/s, cue_physics.c:76
N CUE_CUSH_STEPS impulse increments per cushion impact 96, cue_physics.c:731
vrigid CUE_CUSH_RIGID_V where the rigid-cushion assumption stops holding 2.5 m/s, cue_physics.c:735

Pockets

Symbol Code Meaning Source
Pp pocket[p] pocket point cue_table.c:1481
n^p pmnorm[p] outward mouth normal, from the two nearest jaw tips cue_table.c:3176–3181
Dp drop_c[p] drop / catch / bore circle centre =Pp+n^p b cue_table.c:3184–3188
ap pocket_r[p] drop-circle radius = visible mouth − cap_* cue_table.c:2921
Cp cut_c[p] cut (cloth-edge) arc centre =Pp+n^p s cue_table.c:4368
rpcut cut_r[p] cut arc radius = cut_ref × cut_rad cue_table.c:4369
ℓp lip_d[p] lip roll radius: how far the cloth turns over the cut edge cue_table.c:4370, capped :4398–4404
ρ rr ball-centre arc radius on the lip, ρ=ℓp+R cue_physics.c:1155, :2080
Φp cue_phys_cut_out signed distance past the cloth edge: <0 on cloth, 0 at the edge, >0 over the drop cue_physics.c:1086

VR cue

Symbol Code Meaning Source
a^ CueVrCue.axis cue axis, butt→tip, unit cuevr_cue.c:1704, :2128
t CueVrCue.tip tip position, room space cuevr_cue.c:1705
rtip s_tip_r cue-tip radius cuevr_cue.c:175–180
ϱ reach contact radius =R+rtip cuevr_cue.c:2628
σ,τ tip_side, tip_vert tip contact offset as a fraction of ϱ; +σ right english, +τ top cuevr_cue.c:2866–2867, cuevr_hit.c:41–48
ε elev cue elevation above horizontal (butt raised) cuevr_cue.c:2573, cuevr_hit.c:49–54
σmax CUE_TIP_MAX miscue limit, 0.50 of the radius cue_physics.h:878
δ CUE_SQUIRT_RAD cue-ball deflection (squirt) at full side, 0.0349 rad = 2.0° cue_physics.h:688

1. Ball motion

1.1 State and dimensionality

The world is planar by construction but not by assumption. The header states the convention: "Table plane = world X–Z, Y up; cloth at Y = 0, ball centre at Y = R (v1 is planar — no jumps, vel.y and pos.y are pinned). Each ball carries full 3-D angular velocity w so spin physics is real: the horizontal components are top/back/roll, the vertical (Y) component is side / 'english'" (cue_physics.h:5–8). Vertical motion was subsequently enabled for jump shots, cushion hops and the drop; the cloth-contact path still flattens a falling ball (cue_physics.c:545) while leaving a rising one alone — a fix whose reason is recorded verbatim: "This flattened it unconditionally … and is also why a ball could never leave the cushion: the impact handed it an upward velocity and the next substep of cloth contact threw it away before the airborne test upstairs ever saw it" (cue_physics.c:538–545).

Orientation is integrated separately as a rotation matrix, by rotating about ω^ through ∣ω∣h each substep (ball_spin_orient, cue_physics.c:549–555). It is render-only: nothing in the dynamics reads orient.

1.2 The three cloth-contact regimes

Each substep, for each ball on the cloth, ball_cloth() (cue_physics.c:486–546) computes the slip of the ball's contact point on the cloth,

u  =  v+ω×rc,rc=(0,−R,0),uy≡0,

and u=∥u∥ in the horizontal plane. The regime is decided by comparing u against the maximum slip one substep of full kinetic friction can remove:

Δufull  =  72 μs g h.

The 72 is the combined linear + angular decay rate of the contact-point slip for a uniform sphere: u˙=−(1+mR2/I)μsg=−72μsg with I=25mR2. The code states this: "The contact-point slip |u| decays under kinetic friction at (7/2)·μ_s·g (the combined linear + angular effect for a uniform sphere)" (cue_physics.c:494–497).

(a) Sliding, u>Δufull (cue_physics.c:501–507):

a=−μsg u^,v+=ah,ω+=hI (rc×ma).

This is what develops draw/follow/stun into their eventual roll; the header calls it out as such (cue_physics.h:14–16).

(b) The transition substep, 0<u≤Δufull (cue_physics.c:511–518): the same impulse is applied but scaled by f=u/Δufull<1, i.e. exactly enough friction to zero the residual slip — "energy-exact, no snap bump" (cue_physics.c:509–510).

(c) Rolling (cue_physics.c:521–530): with s=∥(vx,vz)∥,

v+=−μrgh v^(s>Vstop),ωx=vzR,ωz=−vxR.

The angular velocity is slaved to the rolling constraint rather than integrated, so the slip stays identically zero. A sign check zeroes v if the resistance term overshoots (cue_physics.c:525).

Note that U_ROLL (cue_physics.c:34, "0.01 m/s contact-point slip => rolling") is defined but never referenced anywhere in the source; the rolling transition is decided by the Δufull comparison above.

1.3 Vertical spin (english)

ωy decays linearly and independently of the ball's motion, with a deadband (cue_physics.c:533–536):

ωy-=sgn⁡(ωy) αspinhfor ∣ωy∣>Wstop,ωy:=0 otherwise.

with αspin=5μspg/(2R), μsp=0.022, chosen because it "gives a couple of seconds of carry, which matches real side-spin persistence" (cue_physics.c:55–57). This is an approximation: a real ball's vertical spin decays through the same finite contact patch as its roll, and the coupling to the horizontal spin components is neglected entirely.

1.4 Airborne, rail-top and the surface query

A ball is airborne when y>R+10−4 (cue_phys_airborne, cue_physics.c:461). In flight it gets gravity and nothing else — no cloth contact and no air drag (cue_physics.c:2361–2363). The comment is explicit about why this matters: "Its spin is preserved through the flight instead of being turned into roll, so it lands still sliding and skids on, and that is why a jump shot behaves nothing like the same stroke played flat. It is also why this must not happen by accident: a ball that hops unintentionally stops developing roll, and every draw and follow shot quietly stops meaning what it meant" (cue_physics.c:2330–2339).

What is under a ball is decided by surface_at() (cue_physics.c:1888–1932), which returns one of three answers: 0 (cloth), rail_top (cushion top and wood cap as one flat level, =1.30× cushion_h, cue_table.c:2874), or CUE_NO_SURFACE (off the frame, or over a pocket). Landing on a surface applies bed restitution (cue_physics.c:2367–2372):

vy←{−ebed vyvy<−vland0otherwise.

vland is tuned so the last hop is under a millimetre: "below that it settles flat rather than chatter, because every bounce suspends cloth friction and a ball that never quite lands never develops roll" (cue_physics.c:70–76).

A guard prevents a ball that has penetrated a cushion (rather than climbed it) from being teleported onto the rail: if the reported surface is above the cloth but the ball is not yet clear of it, the surface reverts to the bed (cue_physics.c:2347–2359). "Every hard shot does this: the ball penetrates the rail by a millimetre or two before the collision resolves. Treating that as 'over the rail region, so it must be on the rail' teleported it up onto the frame, from where it rolled gently off the table and was deleted."

A ball off the cloth for more than 10 s of simulated time is removed as CUE_OFF_TABLE (cue_physics.c:2400–2405, :2422–2427) — "a frame cannot wait on it: ten seconds and it has left the table, which is what a referee would say."

1.5 Integration scheme and timestep

Semi-implicit (symplectic) Euler: velocities are updated by the contact/friction terms first, then x+=vh (cue_physics.c:2438–2441). On the cloth y is then pinned to R.

The substep is fixed at

h=12000 s,

driven by an accumulator from the frame dt (cue_phys_step, cue_physics.c:2609–2617):

w->_acc += dt;
while (w->_acc >= h && iters < CUE_MAX_SUB) { substep(...); w->_acc -= h; iters++; }
if (iters >= CUE_MAX_SUB) w->_acc = 0.0f;   /* shed backlog */

with CUE_MAX_SUB = 400 (cue_physics.c:19). The rate is justified by the tunnelling bound: "2 kHz keeps a fast break (≈6 m/s) to ~3 mm of travel per step — well under a ball radius, so overlap-based collision resolution never tunnels" (cue_physics.c:15–17).

cue_phys_set_substep() (cue_physics.c:2569) allows a coarser step for headless ranking simulations; per the AI review the default is now the live 1/2000 (see §8).

Sleeping. A ball with ∥(vx,vz)∥<Vstop, ∣ωy∣<Wstop and ∣ωx∣,∣ωz∣<0.05 skips the cloth and integration step entirely (cue_physics.c:2433–2437); it is woken implicitly by any collision that gives it velocity. "This is exact (a still ball doesn't move) and is the big win on this low-drag cloth, where a shot's long roll-out leaves most balls stopped for ~100+ substeps each." When the whole table settles, cue_phys_step zeroes all of v and ω (cue_physics.c:2642–2653), for a measured reason: "a resting ball with stored spin is not resting: ball-ball friction reads BOTH spins at the next contact, so the residual bent the throw of the NEXT shot. Measured at 0.2 mm of settle divergence from one quiet stroke into once-rolled balls."

1.6 The strike (impulse model)

cue_phys_strike_jump() (cue_physics.c:371–446) is the single entry point; the two simpler forms are wrappers with ε=0 and/or vy=0 (:448–456).

Given aim direction f^ (flattened, normalised), speed V, tip offsets (σ,τ), elevation ε and bed-launch speed vy:

  1. Frame. r^=y^×f^^ (the shooter's right); the cue direction is c^=(fxcos⁡ε, −sin⁡ε, fzcos⁡ε) (cue_physics.c:377, :387).
  2. Squirt. The departure direction is the aim rotated by −σδ about vertical: d^=f^cos⁡(−σδ)+r^sin⁡(−σδ)^ (cue_physics.c:403–405). δ is a setting (cue_phys_set_squirt, cue_physics.c:364) with default 2.0°, range 0–5.0° (cue_physics.h:688–695).
  3. Departure velocity. v=Vcos⁡ε d^, vy set separately (cue_physics.c:406–411).
  4. Tip offset clamped to the miscue limit: if σ2+τ2>σmax=0.50 both are scaled down (cue_physics.c:437–439).
  5. Spin. The lever arm is built in the cue's own frame: u^=c^×r^^, r=σR r^+τR u^, J=Vm c^, and
ω=r×JI=52 VR (σ r^+τ u^)×c^.

Hence ωR/V=2.5 ∣(σ,τ)∣, so the clamp at 0.50 gives a maximum of 1.25, "which is the real maximum" (cue_physics.c:428–439, cue_physics.h:866–879).

Two deliberate departures from naive modelling are recorded here.

There is no miscue model at all — a contact beyond the limit is simply held to it (cue_physics.h:874–876). This is an explicit modelling choice, not an omission.


2. Ball–ball collision

collide_ball_ball() (cue_physics.c:558–647). One resolution per pair per substep, in a double loop over i<j (cue_physics.c:2457–2495) with a per-axis broad-phase reject at 2R (the set's own diameter, safe because a smaller cue ball only shrinks the pair sum, cue_physics.c:2453–2463).

2.1 Detection

The separation test is planar when both balls are on the cloth (identical y, so "the same test it always was for every shot that does not leave the bed — including the arithmetic, which is why nothing that used to work moves by a bit", cue_physics.c:559–566) and becomes a genuine 3-D sphere test when either is airborne (cue_physics.c:569–578):

Δxz2+Δy2<(Ri+Rj)2.

2.2 Positional de-overlap

The overlap is split and each ball displaced along n^ by 12(Ri+Rj−d) (cue_physics.c:587–590). The comment and the code disagree here: the comment says "Split by SIZE, so a small cue ball is pushed further than the object ball it met", but the code applies an equal 0.5 split. Reported as observed; the source does not explain the discrepancy.

2.3 Normal impulse

With vn=(vj−vi)⋅n^ and separation early-out vn≥0 (cue_physics.c:593–594):

Jn=−(1+ebb) vn1/mi+1/mj,vi-=Jnn^mi,vj+=Jnn^mj.

Written with both masses because "English pool's cue ball is lighter than the balls it strikes — 94 g against 116 — and with equal masses this is exactly the old m/2 reduced mass" (cue_physics.c:596–600).

2.4 Tangential impulse — throw is modelled, not faked

The relative surface velocity at the contact is formed from both spins (cue_physics.c:607–612), with ri=+Rin^, rj=−Rjn^:

s=(vj+ωj×rj)−(vi+ωi×ri),st=s−(s⋅n^)n^.

The tangential effective inverse mass at a sphere contact is 1/m+r2/I=7/(2m), independent of radius, so the pair gives (cue_physics.c:616–622):

kt=72mi+72mj,Jt=min⁡ ⁣(∥st∥kt, μbb∣Jn∣).

This is a Coulomb cone with a stick branch: either the slip is arrested exactly, or the friction saturates. Both linear and angular impulses are applied to both balls (cue_physics.c:640–643). Throw and spin transfer therefore emerge rather than being added on — as the header puts it, "ball–ball throw and english-off-the-cushion fall out of the same framework rather than being faked" (cue_physics.h:19–21).

The direction is load-bearing, and the source records the bug and its measured cost in full:

"That inverts throw. Measured out of the engine (test_throw.c), a plain cut with no side threw the object ball up to 4 degrees off the ghost-ball line and in the WRONG DIRECTION — a cut was overcut where every real table undercuts. On a one-metre pot 4 degrees is 68 mm, which is most of a snooker pocket … It also made side unusable: turn it on and every sided shot missed by the throw." (cue_physics.c:626–639)

Both balls' vy are zeroed after the resolve (cue_physics.c:645), so a ball–ball contact is always planar in its outcome even when one ball is airborne.

2.5 Simultaneous and repeated contacts

There is no simultaneous solver and no manifold. Pairs are resolved one at a time, in index order, once per substep. Repeated and near-simultaneous contacts (a break pack) are handled purely by the substep rate: at 2 kHz a 6 m/s ball advances 3 mm per step, so a chain of contacts is resolved over successive substeps rather than at once. This is an approximation to a simultaneous impulse solve; the source does not claim otherwise, and the tunnelling argument at cue_physics.c:15–17 is the whole justification given.


3. Cushion impact

This is the most elaborate model in the engine, and the one whose comments are the most useful.

3.1 Why the single-impulse model was abandoned

The header comment on cushion_impact() (cue_physics.c:696–729) states the case:

"The cushion used to be handled by collide_surface above: one instantaneous Coulomb impulse against a tilted wall. That model is in a class which provably cannot do what a real cushion does. Biber, Champneys & Szalai (arXiv:2208.11685) show that a rigid contact with a Poisson or energetic restitution 'cannot capture slip reversal during the contact phase' — the slip direction is frozen at the instant of contact — and that the fix is to let the impact take TIME, during which the slip direction rotates."

The scheme implemented is Mathavan, Jackson & Parkin, A theoretical analysis of billiard ball dynamics under cushion impacts, Proc IMechE Part C 224:1863 (2010), eqs. 14a–14f, integrated over the accumulated normal impulse rather than over time. The paper's own constants are quoted (ee=0.98, μw=0.14, μs=0.212, h=7R/5 so sin⁡θ=2/5) and noted as being measured on a Riley Renaissance with snooker balls, i.e. "this game's own sport rather than a generic sphere" (cue_physics.c:705–717).

The critical structural point: two contacts act at once — the cushion at I and the cloth at C — "and that second one is why the old model could not be fixed by tuning: it was not there at all" (cue_physics.c:718–720).

3.2 Contact selection and geometry

collide_cushions() (cue_physics.c:941–1037):

The contact height is computed per impact, not taken from the table spec (cue_physics.c:1003–1007):

ynose=R cush_sin,rise=y−R,sin⁡θ=clamp⁡ ⁣(ynose−riseR, ±0.95).

so a ball already in the air meets the nose lower down, and once the contact is below centre the same impulse points up. The reasoning is stated as geometry rather than as a rule: "That falls out of the geometry rather than needing a rule" (cue_physics.c:988–1002).

cush_sin is filled from the table: sin⁡θ=(cushion_h−R)/R, with cushion_h =1.27R on almost every table — "63.5% of the ball, which is the WPA specification" (cue_table.c:2843–2846, cue_table.c:66–68). It is stored as sine and cosine, never as an angle, specifically to avoid a asinf/cosf/sinf round trip through the platform's libm (cue_physics.h:195–203).

3.3 The impact frame

cushion_impact() (cue_physics.c:747–929) works in the paper's frame: y^ horizontal into the cushion (=−nface flattened and normalised), x^=y^×z^world^ along the cushion, z^ world up (cue_physics.c:751–756). State is projected: vx,vy,vz and ωx,ωy,ωz (cue_physics.c:758–765). S=sin⁡θ, C=1−S2.

3.4 Speed-dependent restitution

ζ0=vyC+vzS(approach speed along the contact normal),
e(ζ0)=clamp⁡(e0−ke ζ0, emin, e0).

(cue_physics.c:784–786, :798.) The comment states the empirical basis and what went wrong with a constant:

"A constant was measurably the wrong SHAPE, not merely the wrong number: square into the rail this model returned 89-90% of the speed at 2 m/s and the same 89-90% at 7, so a firm shot lost nothing extra and every angle off the rail played the same however hard it was hit. Mathavan's high-speed imaging of a snooker table has the rebound ratio at 0.910 for a ball barely moving and a 0.818 best fit across 0.28-3.5 m/s … and Marlow's rails come in near 0.55 — which is where a really firm one ends up. Linear in the approach speed, anchored on those two, floored so it cannot go absurd on a break." (cue_physics.c:774–783)

Per-table values are set in cue_table_rails() (cue_table.c:76–109): US pool K-66 worsted e0=0.985, ke=0.046; UK 8-ball 0.965/0.052; Chinese 8-ball 0.968/0.050; carom K-55 on a heated table 0.990/0.038 ("the ball is meant to hold speed through three rails, which no pool cushion is asked to do"); snooker 0.970/0.050; and one home table deliberately deader, 0.930/0.062. The block comment records that these are inputs, tuned against measured output: "So they were tuned against the MEASURED rebound, not set to the published figure and hoped for: snooker lands on 83% at 2 m/s, 76% at 3.5 and 61% at 7, against Mathavan's 0.818 across normal play and Marlow's 0.55 for a hard one" (cue_table.c:70–75).

3.5 Low-speed bypass

If ζ0<0.025 m/s the impact is not integrated at all; the normal velocity is simply reflected, vy←−e vy (cue_physics.c:798–803). "A BALL LEANING ON THE CUSHION IS NOT AN IMPACT … running the full scheme there lets it settle a few millimetres the wrong side of the cushion line in a mitred pocket corner, where the segment normals fight each other."

3.6 The impulse-stepped integration

Total normal impulse Ptot=(1+e)Mζ0, taken in N=96 equal slices dP=Ptot/N (cue_physics.c:805–808). The loop is allowed up to 6N=576 iterations (cue_physics.c:815); the slice count is justified as "96 lands within 0.1% of 512" (cue_physics.c:731).

Per slice, the slip velocities at the two contacts are (cue_physics.c:817–822):

sI(n)=−vyS+vzC+ωxR,sI(d)=vx+ωyRS−ωzRC,sC(n)=vy+ωxR,sC(d)=vx−ωyR,

with slip angles φ=atan2⁡(sI(n),sI(d)) and φc=atan2⁡(sC(n),sC(d)) — used only through their sine and cosine, which are obtained algebraically as s(d)/r and s(n)/r (see §7.2). Friction coefficients are gated on actual slip: μw active iff ∥sI∥2>10−8, μs active iff the ball is on the cloth (y≤1.02R) and ∥sC∥2>10−8 (cue_physics.c:845–855, :790).

The cloth's share of the impulse (the paper's eq. 8) is

kC=S+μwsin⁡φ C,kC+=max⁡(kC,0) (and 0 in the air).

(cue_physics.c:857–860.) The clamp is the physical statement that a cloth cannot pull downwards.

The per-slice increments (cue_physics.c:862–868), with γ=5 dP/(2MR):

dvx=−dPM(μwcos⁡φ+μscos⁡φc kC+)dvy=−dPM(C−μwSsin⁡φ+μssin⁡φc kC+)dvz=+dPM(kC+−kC)dωx=−γ(μwsin⁡φ+μssin⁡φc kC+)dωy=−γ(μwcos⁡φ S−μscos⁡φc kC+)dωz=+γ μwcos⁡φ C

dvz is zero while the cloth holds (kC≥0) and becomes a lift when kC<0: "A cloth cannot pull downwards, so when that goes negative the table has lost the ball and the vertical velocity is free — the ball lifts. That is the real trigger, not a special case bolted on" (cue_physics.c:722–728).

Termination is energetic (Stronge), not kinematic. The work done by the normal impulse is accumulated trapezoidally, W+=dP⋅12(ζ+ζ′) (cue_physics.c:873–875). Compression ends the first slice at which ζ≤0, recording Wc; restitution ends when

W≤(1−e2) Wc

(cue_physics.c:876–878) — i.e. the contact returns exactly e2 of the compression work. A second break guards a degenerate case where W has gone to zero while still closing.

3.7 The post-rigid lift — an explicit extrapolation

Everything above lives inside the rigid-cushion assumption, in which the ball cannot leave the table. Above vrigid=2.5 m/s of normal approach the code adds a climb (cue_physics.c:904–923):

over=ζ0−vrigid,rollin=clamp⁡ ⁣(−ωx,0R∣vy,0∣+10−3, 0, 2),
lift=0.10⋅over⋅(0.5+0.5 rollin),lift≤2g⋅0.55⋅RS.

The source labels this plainly, and it is the one place in the cushion model where the authors say they are outside the literature:

"This is EXTRAPOLATION, not measurement: nobody has published outgoing vertical velocities off a cushion, and this is a plain ramp in the excess over the rigid limit, scaled by how much the ball is rolling INTO the nose, which is the direction of climb." (cue_physics.c:896–899)

The cap has a measured justification: "Measured: at the uncapped value, four shots in a thousand ended up resting the wrong side of the cushion line" (cue_physics.c:910–918). Finally vy is clamped ≥0 — the cushion is never allowed to drive a ball downward (cue_physics.c:927).

3.8 Jaw circles — the simple model, retained

Jaw tips are immovable discs of radius jaw_r handled by collide_surface() (cue_physics.c:1022–1035, :652–694), i.e. a single instantaneous impulse against a horizontal normal:

Jn=−(1+e0) vn m,Jt=min⁡ ⁣(∥vt∥7/(2m), μw∣Jn∣),

with the angular impulse's vertical component scaled by κ=0.30 (cue_physics.c:688–690) so "the rail imparts much less NEW english … while the horizontal (roll) axis keeps full friction so roll is correctly damped — no over-spin build-up, and incoming english still bent the bounce above". Friction is skipped entirely when −vn<0.025 m/s, because "a ball merely rolling ALONG the rail has a near-zero approach speed and must not be braked every substep (that was the 'sticking')" (cue_physics.c:666–669).


4. Pocket geometry and capture

4.1 Three circles

The engine distinguishes three concentric-ish circles per pocket, all derived from the pocket point Pp and the mouth normal n^p:

(i) The bore / drop / catch circle. Centre Dp=Pp+n^p b where b is drop_back (corner) or drop_back_side (middle), radius ap= pocket_r[p] = visible mouth − cap_* (cue_table.c:3184–3188, :2921). This one circle does four jobs, and the source is emphatic that they must not diverge:

cue_table_normalise() (cue_table.c:2784–2790) makes the timber's bore identical to this circle by construction; its underside is cue_table_bore_bot() =−2 mm (cue_table.c:4527).

(ii) The cut circle — where the slate and cloth actually end. Centre Cp=Pp+n^p s with s= cut_set, radius rpcut= cut_ref × cut_rad, where cut_ref is the visible mouth (pr_corner/pr_side), not the drop radius (cue_table.c:4366–4370, :3214). The comment records why they were separated: "rad used to be a multiple of the DROP circle, which meant the cut could not be held still while the drop was moved" (cue_table.c:4196–4200). The header adds the physical point: "at a middle it happens well before the jaws, at a corner slightly after them" (cue_physics.h:358–366).

(iii) The lip roll, radius ℓp= cut_ref × cut_roll (cue_table.c:4370), the quarter circle the cloth turns over the cut edge. A ball riding it has its centre on an arc of radius ρ=ℓp+R. This radius is capped so a ball can always reach the end of the roll before it reaches the deepest point it can physically get to (cue_table.c:4398–4404), a fix with an unusually precise motivation:

"On a Russian pyramid corner … the mouth is 72 mm for a 67 mm ball, and the deepest a ball can ever get is the middle of the pocket, where it was 0.9 MILLIMETRES short of the release. So it sat there. Dead centre in the pocket, at cloth height, held up by a roll it could not reach the end of, with the shot never settling and the frame unable to continue. 42 shots in 1890 on the 12 ft and 37 on the 7 ft." (cue_table.c:4372–4397)

Per-table values of (s, rad, roll, arc) are tabulated in cue_table_default_cut() (cue_table.c:4193–4325); the snooker corner is read off a WPBSA 3MF gauge as "an arc r 3.5 in (88.94 mm fitted) CENTRED ON THE SLATE-EDGE CORNER" (cue_table.c:4221–4231).

4.2 cue_phys_cut_out() — the cloth cut as a signed distance field

cue_physics.c:1086–1108. Returns how far past the cloth edge a point is: negative on slate, zero at the edge, positive out over the drop. The cut is "an arc around cut_c with a straight tangent leg out to each slate edge — a quarter circle at a corner, a half at a middle. That makes the distance to it exact and cheap: which of the three pieces is nearest falls out of the sign of the point's two local coordinates, so there is no search" (cue_physics.c:1078–1085).

Let r=rpcut, sx=sgn⁡(Cx), sz=sgn⁡(Cz), u=sx(x−Cx), v=sz(z−Cz) (local coordinates with the table interior at u,v≤0).

A hole in the open bed (bar billiards, pocket_bed[p]): the cut is a circle and nothing else,

Φ=r−(x−Cx)2+(z−Cz)2.

The reason is recorded: run through the legged form, "those legs claimed half the table as 'no cloth here' — which is exactly the reported fault of pockets gathering balls from nowhere near them" (cue_physics.h:325–333).

A middle pocket (half arc, two parallel legs), with u=x−Cx unsigned:

Φ={r−∣u∣v>0(between the legs)r−u2+v2v≤0(facing the arc)

A corner (quarter arc, two perpendicular legs):

Φ={r−u2+v2u≤0, v≤0(facing the arc)min⁡(u,v)+ru>0, v>0(deep in the cut)u+rv>0, u≤0v+rv≤0, u>0

The surface normal is taken numerically, by central differences of Φ with ϵ=10−4 m (cue_physics.c:1193–1200, and again at :2164–2171), giving the in-plane gradient direction "into the cut".

Observation, reported as read: this function branches on p >= 4 to decide "middle" (cue_physics.c:1097), as does cue_phys_drop_walls (cue_physics.c:1179). That is the index-based assumption the header explicitly warns against for L-shaped beds — "an L has FIVE corners, so all three would have called its fifth corner a middle" (cue_physics.h:343–348) — which the rest of the code answers with pocket_mid[]. The source does not reconcile the two.

4.3 Tipping over the lip

Once flagged as dropping, a ball is stepped by cue_phys_drop_mesh() (drawn geometry in the solver) or cue_phys_drop_fall() (gravity + drag + move), then constrained by the lip (cue_physics.c:2108–2236) if there is no drawn lip mesh.

With o1=Φ(x,z)>0 and ρ=ℓp+R, the cloth surface height under the ball's centre is

ylip=ρ2−o12−ℓp,dydo=−o1ρ2−o12=slope,cos⁡ϑ=11+slope2.

(cue_physics.c:2137, :2162–2163.) The tangential direction t^ points down the roll; vt is the ball's speed along it. Contact is decided by height and by whether gravity can hold the ball to the arc (cue_physics.c:2178):

held  ⟺  vt2≤g ρ cos⁡ϑ.

This is the standard "ball leaves a convex surface when mv2/ρ>mgcos⁡ϑ" criterion, and it is what makes a firm pot look different from a dying one, as the comment observes: "The roll only holds a ball that is slower than sqrt(g(ld+R)), about 0.7 m/s; anything above that leaves the edge and flies, and that falls out of the same two lines rather than being asked for" (cue_physics.c:2104–2107; a second comment at :2144–2146 quotes gρ=0.59 m/s for its own table).

While held, only the velocity component into the surface is removed (cue_physics.c:2187–2192), and gravity rolls the ball down the slope at the rolling-without-slipping rate (cue_physics.c:2209–2216):

Δvt=57 gsin⁡ϑ h,Δω=Δvt/R.

The comment records a sign-and-share bug in this exact expression: "This had the sign inverted and the wrong share — it applied 2/7 g sin(th) UP the roll, so a ball on the lip was being braked by the very thing that should have been taking it down, while the 5/7 went into spin that nothing was coupled to. That is a ball sitting on the lip turning over, on every table" (cue_physics.c:2199–2208). A related comment forbids charging the ball twice for the rise: "the tangential gravity term above has ALREADY taken that height out of its speed — charging again is counting it twice, and counting it against the whole velocity is what deleted a ball's motion across the lip" (cue_physics.c:2218–2226).

An earlier, discarded approach is documented in full at cue_physics.c:2150–2161 ("WHY NOT 'vel.y = the roll's rate'"), including its symptom: "A slow ball toppled at a tenth of gravity: 'balls on the lip fall in slow motion'."

A ball whose whole width is inside the throat wall is declared over open pocket (over_open, cue_physics.c:2127–2129) and the lip constraint is skipped — "makes 'a ball parked on top of a pocket' a shape the physics cannot express, rather than one it merely happens not to reach."

4.4 Capture

check_pockets() (cue_physics.c:1718–1812):

  1. A ball whose underside is above rail_top is flying clean over and cannot be potted (:1719).
  2. Broad reject at rpcut+3R from Dp, which also clears the per-hole "already judged" flag (:1721–1731).
  3. Primary test: the drop circle. ∣x−Dp∣2≤ap2 (:1737).
  4. Secondary test: no cloth under it. If the circle missed but Φ>0, the ball is over the cut and is potted (:1771).

The evolution of this test is one of the most instructive comments in the file (cue_physics.c:1739–1770). A jaw-line half-plane test was tried and removed — "a straight line has no ends. Combined with the proximity test it captured a HALF DISC, and at a corner a ball hugging the rail crosses that line well to the side of the mouth — pot area in FRONT of the pocket, which is the one place there must be none." The circle alone was then validated: "1044 shots per table at every pocket, speed and angle, and 16,632 more fired hard from twenty angles, all lose nothing with the circle alone." And when a leak reappeared after re-tuning ("pushing the US table's catch 0.28 R deeper put it behind where a hard ball crosses the throat, and four went off the back of it"), the replacement was the Φ>0 test rather than a new rule.

On capture: pocket is recorded; with cue_phys_set_fast_pot on the ball is removed immediately, otherwise drop = 1.0 starts the fall (cue_physics.c:1805–1806). The fast-pot switch exists for the planner and carries its own measurement: "Measured on a 10 ft snooker table (2026-09-06): plans averaging 1373 ms with the fall in them" (cue_physics.c:1786–1804).

Bed holes (bar billiards) are judged once, on the substep the centre crosses in (cue_physics.c:1778–1782), by a free-fall argument in bed_hole() (cue_physics.c:1660–1716). With hole radius a, perpendicular miss distance p=∣d×u^∣ and chord half-length η=a2−p2:

span=2η,t=spanv,fall=12gt2,caught  ⟺  fall≥hole_catch⋅R

with hole_catch =0.66 (cue_physics.c:52). The whole character of the game is derived from this one line: "you can pot the 200 from anywhere on the table, but only at a pace that gives it time to drop, and thumping it just skips it across the hole" (cue_physics.c:1654–1657). A rim-out is given a restitution e=0.15+0.55f against the far lip, horizontal damping (1−0.2f) and an upward kick 0.35(0.3+0.7f)v, with f=fall/need (cue_physics.c:1696–1713). The whole chord is used, not the remainder, and the reason is a determinism argument: "the live game samples at 2 kHz and the AI ranks shots at 600 Hz, so the AI would have judged the same shot harder than it is and stopped playing pots that go in" (cue_physics.c:1677–1686).

4.5 What is under the cloth

cue_phys_drop_walls() (cue_physics.c:1153–1282) supplies analytic walls where a table has no drawn geometry (the handheld, the tests): the cut's vertical face through the bed (using Φ and its numerical gradient), the pocket's iron bridge, and a funnel "bag" whose radius interpolates linearly from the cut's reach at the mouth to 1.14R at a ring 3.9R below (cue_phys_bag_r, cue_physics.c:1144–1150).

The iron does not play the ball back; it turns horizontal speed into fall (iron_down, cue_physics.c:1395–1400) with an explicit energy cap:

vy′={vy−0.75 vuif (vy−0.75vu)2≤vy2+vu2−vy2+vu2otherwise.

The reason is a measured energy leak: "Written as vy -= k*vu that quietly created energy whenever the ball was already falling — the two add, and the square of the sum is more than the sum of the squares. On a pool table … the pocket test caught it fifteen times and up to 1.75 J/kg, which is 1.9 m/s conjured out of nothing" (cue_physics.c:1387–1394).

Where the app supplies drawn meshes, cue_phys_drop_mesh() (cue_physics.c:1436–1516) hands the ball to the general rigid-body solver against every static surface under the cloth at once — the lip, the return box, and each pocket's solid and net (cue_phys_under_bodies, :1295–1319) — with materials: leather over iron μ=0.35, e=0.06; net μ=0.30, e=0.02; moulded return μ=0.20, e=0.12; cloth lip μ=0.05, e=0.08 (cue_physics.c:1284, :1307–1316). The lip's very low friction is itself a documented finding: "At the solver's 0.22 the lip was a rubber gripper: the friction solve drives the contact's slip to zero every substep, so the ball was spun up to match the speed it gained going down, which is a gear and not a pot" (cue_physics.c:1321–1330).

4.6 The jaw / knuckle chain

Cushions are a chain of CueSeg records — endpoints a,b, face normal n, the two vertex normals na,nb, and a kind flag (0 rail nose, 1 pocket facing/jaw) (cue_physics.h:171). Construction (cue_table.c):

A dropping ball still meets the jaws and cushions while any of it is above the cloth, with its effective radius shrunk to the chord at its current depth, reff=R2−y2, "so it slips under the noses the way a ball does and can never leave through the side of a cushion" (cue_physics.c:2267–2301). The vertical velocity is explicitly preserved across that call, because collide_surface zeroes it (cue_physics.c:2280–2292).


5. The under-table solver (mote_phys.c)

A general sequential-impulse rigid-body solver with warm starting. It runs the bar billiards skittles and everything below the cloth. Header summary: "Sequential-impulse solver with WARM-STARTING … Warm-starting is what lets tall stacks stay stable in a handful of iterations — without it, Gauss-Seidel propagates floor support only one body per iteration and deep stacks sink/collapse" (mote_phys.c:1–13).

5.1 Constants

Constant Value Source
DEFAULT_H 1/240 s (per-world overridable; CueVR sets h=1/2000) mote_phys.c:27, cue_physics.c:234
SOLVER_ITERS 8 velocity iterations per substep mote_phys.c:29
POS_ITERS 4 position iterations mote_phys.c:30
MAX_SUBSTEPS 8 (CueVR/ThumbyCue: 400) mote_phys.c:31, cue_physics.c:235
REST_SLOP 0.45 m/s — below this e=0 mote_phys.c:28
POS_BETA 0.2 Baumgarte factor mote_phys.c:32
POS_SLOP 5 mm allowed penetration, but never more than POS_SLOP_REL=2% of the body mote_phys.c:33–35, :915–919
WAKE_PEN / WAKE_VEL 0.02 m / 0.30 m/s mote_phys.c:36–38
SLEEP_DIST2/ANG2/VEL2/FRAMES 25 mm, 0.40 rad/s, 0.02 m/s, 20 substeps mote_phys.c:39–47
SLEEP_LEVEL_COS2 cos⁡2(0.25°) mote_phys.c:64

5.2 Inertia

No inertia tensor is stored; the world-space inverse inertia is a body-frame diagonal rotated into world (iinv_mul, mote_phys.c:95–115):

5.3 Contact generation

Broad phase is a uniform grid when n>24 bodies (cell size 2rmax, grown ×1.5 until the cell count fits), else all-pairs (mote_phys.c:951–1029, :1084). Static planes and static meshes are excluded from the grid and tested against every awake dynamic body each substep (mote_phys.c:1101–1108). Mesh colliders use a 2-D XZ grid, testing the 3×3 cells around the body (gen_vs_mesh, mote_phys.c:698–723).

Narrow phase dispatch (gen_pair, mote_phys.c:741–756):

Pair Method Contacts
sphere–sphere analytic 1 (:210–218)
sphere–box nearest point on OBB, with a deepest-axis fallback when the centre is inside 1 (:318–339)
box–box SAT over 15 axes + reference-face clipping up to 4 (:251–315)
box/hull–box/hull Cvx expansion + face_query SAT + incident-face clip up to ~4 (:578–632)
anything with a capsule (round) GJK + EPA 1 (:729–739)
vs plane per-shape: sphere point, capsule two ends, hull every vertex, box eight corners many (:759–791)
vs mesh per triangle; faceted bodies get a clipped manifold, round bodies a face-normal point many (:662–695)

Each contact stores a warm-start key hashed from the two body indices and a feature id (add_contact, mote_phys.c:196–205).

The per-shape plane test is not incidental: the skittle world uses real static planes rather than the solver's own bounding-box walls because "those test a hull as a box of its half extent — which a hull does not set, so the box is a point at the centre of mass and a pin sinks to its own middle before anything stops it. gen_vs_plane tests a hull vertex by vertex, which is the shape actually being asked about" (cue_physics.h:495–501).

5.4 Velocity solve

prepare() (mote_phys.c:829–861) precomputes, per contact:

solve_vel() (mote_phys.c:863–883), run SOLVER_ITERS times, is textbook projected Gauss–Seidel:

Δjn=b−vnkn,jn←max⁡(0, jn+Δjn),
Δjt=−vtkt,jt←clamp⁡(jt+Δjt, ±μjn),

with only the increment applied each time, so the accumulated impulse is what is clamped.

The friction cone is reduced to a single direction. There is one tangent t^ per contact, fixed at prepare() time from the initial slip, and one scalar jt clamped to ±μjn. This is neither a two-direction pyramid nor a true cone projection; it is exact when the slip direction does not rotate during the solve and approximate otherwise. The source does not discuss this choice.

5.5 Split-impulse position correction

Penetration is removed through a separate pseudo-velocity field that integrates into positions only (mote_phys.c:889–942): "it never touches real velocity, so deep simultaneous landings can't explode the way Baumgarte-in-velocity does."

target=β clamp⁡(pen−slop, 0, 0.2)h,Δjp=target−v~nkn,jp←max⁡(0,jp+Δjp),

with β=0.2. After POS_ITERS sweeps, positions and orientations are advanced by v~h and ω~h and the orientation re-orthonormalised (mote_phys.c:1118–1131).

The slop is relative to the body, and this is a measured fix (slop_for, mote_phys.c:905–919):

"A flat POS_SLOP is a fraction of a crate and a fifth of a snooker ball, and what it costs is not the look of it: the contact point is on the surface, so a ball sunk 5 mm of its 25.4 mm is spun by friction about a 20 mm arm rather than its own radius. Measured on a bare mesh slope, that is 28% too much spin for the speed and 60% of the (5/7)g sin(theta) a rolling ball is owed — enough that a ball trickling onto a pocket lip stopped dead and sat there for nearly three seconds."

5.6 Integration and damping

integrate() (mote_phys.c:1066–1077): semi-implicit Euler with implicit linear and angular damping,

v←v+gh1+λvh,ω←ω1+λωh,x+=vh,

then a world-axis rotation of the orientation and m3_orthonormalize.

5.7 Sleeping, and the "level support" rule

A body sleeps only when it is in contact, not deeply overlapping, barely displaced, barely rotating and barely moving, for SLEEP_FRAMES=20 consecutive substeps (mote_phys.c:1210–1212):

touch ∧ level ∧ pen<12 mm ∧ ∥Δx∥<25 mm ∧ ∥ω∥<0.40 ∧ ∥v∥<0.02.

The velocity term is itself a recorded fix: "Displacement and spin alone let a ball that had just landed on a slope — moving, not yet turning, still inside 25 mm of where it touched down — fall asleep after twenty substeps and stay there for ever … Two centimetres a second is not at rest" (mote_phys.c:41–46).

The level-support rule applies to spheres only (mote_phys.c:1191–1201). Let Ji be the total contact impulse on body i and Jˉi its exponential moving average with k=0.12 (mote_phys.c:1189–1190). Then

level  ⟺  (−Jˉ⋅g)>0 ∧ (−Jˉ⋅g)2>cos⁡2(0.25°) ∥g∥2∥Jˉ∥2.

"A ball has nothing to hold it on a slope — it rolls — so it may sleep only when the net normal impulse on it points straight against gravity, within half a degree: a level floor, a groove, a hollow. Boxes, capsules and hulls keep the old rule; they have faces and friction to rest on" (mote_phys.c:1139–1147).

Two things had to be right for this to be reachable, and both are documented as bugs found in play:

The threshold itself is derived rather than tuned: "A ball coasting through zero on a slope of angle T is held by an impulse tilted from vertical by atan((5/7) tan T) — 0.536 degrees on the ball return's three-quarter-degree gully. That is the case this test exists to reject, so the gate must be well inside it, and a quarter of a degree is" (mote_phys.c:48–64).

Sleeping bodies act as immovable anchors: eff_im() returns 0 and iinv_mul() returns zero for them (mote_phys.c:92, :96), "so an awake body resting on them can't push them around (which used to collapse stacks)." They wake on deep intrusion (WAKE_PEN) or a fast approach (WAKE_VEL) (wake_check, mote_phys.c:985–994), or on being displaced past SLEEP_DIST2 (:1205–1209).

5.8 Skittles as an application

Each bar billiards pin is a convex hull of revolution — foot centre, foot rim (1.62 stem radii at 0 height), cap rim (3.40 radii at 97 mm), top — built once by skittle_hull_build() (cue_physics.c:118–193). The choice is explained: a stem-width capsule "is not the shape the CLOTH meets. A mushroom lying down rests on the rim of its cap and the flare of its foot, and a stem-width capsule has neither: the pin lay down with its head buried in the bed" (cue_physics.c:94–108). The ball, however, is tested against the stem capsule (check_skittles, cue_physics.c:1564–1586), because Rule 74 keeps every ball on the plain cylinder.

The ball–pin impulse is resolved by hand (cue_physics.c:1593–1631) with e=0.15 and the effective inertia taken from mote's own hull rule, so the two solvers cannot disagree. A pin is down when its own axis has left vertical by more than cos⁡−1(0.70)≈45° (cue_physics.c:2031), and nudged when it ends more than 1.5 mm off its spot (:2041–2044) — "That used to be a speed threshold at the moment of contact, which was a guess standing in for an outcome; now the body has an outcome and it can simply be read."

The pin world runs on the same clock as the balls, h=1/2000 with 400 substeps, "so a pin and a ball cannot disagree about when a contact happened" (cue_physics.c:232–235).


6. The VR cue and the strike measurement

6.1 Two ways of building the cue line

Mode A — two controllers (cuevr_cue.c:2055–2286). The bridge is a rigid offset in the bridge controller's own frame:

b=pL+R(qL) o,a^=b−pR^

(cuevr_cue.c:2104–2105, :2117–2128). The offset is in the controller frame, not the room's, for a reason recorded in full: "It used to be a world-space vector added to the controller, which is right only while you stand where you were standing when you set it. Walk round to the other side of the table and 'five centimetres that way' still means the same direction in the ROOM" (cuevr_cue.c:2084–2103). The minimum hand separation is 5 cm (:2118), lowered from 10 cm because "Some players hold both controllers out in front of them, close together like a trombone".

The stroke is armed by the grip-hand trigger with wide hysteresis, 0.55 up / 0.15 down (cuevr_cue.c:2303). The reason is worth quoting because it is a measurement problem, not an input problem:

"A single threshold is what made the power a lottery. An index trigger is analogue and your whole arm is moving during a delivery, so finger pressure dips — and one dip below the threshold disarmed the stroke, the next frame re-armed it, and re-arming resets the sample window, the clock and the locked tip. The measurement restarted from nothing with a one-frame baseline, at a random point in the delivery. And it was invisible." (cuevr_cue.c:2288–2302)

On arming, the line is locked: lock_axis, lock_butt0 (the grip hand's position), lock_tip0 (cuevr_cue.c:2318–2350). Thereafter the tip is a point sliding along that fixed line by the butt hand's travel along it:

travel=(pR−pR,0)⋅a^lock(cuevr_cue.c:2360).

Mode B — a rigid tracked cue (cuevr_cue.c:1685–2053), a real stick with a controller clamped to it:

a^=R(qC) aattach^,t=pC+R(qC) tattach

(cuevr_cue.c:1704–1705). There is no trigger at all: "A real cue plays the ball when the tip reaches it" (cuevr_cue.c:2037–2045); a stroke re-arms when the tip pulls more than 50 mm off the ball (:1911–1914). Three attempts to filter or predict this line are recorded as having been tried and reverted: "each made the drawn cue lag the real one and drift out of step with it, which is worse than the coning they were meant to fix. The cue is where the controller says it is, every frame" (cuevr_cue.c:1696–1703).

The distinction between the two modes is not cosmetic; it changes what the pose ring is allowed to reconstruct (cuevr_cue.c:1412–1429):

"A REAL CUE is a rigid body clamped to one controller: rotate the controller and the tip swings a metre and a half away, which is most of where its speed comes from. The ring rebuilds it by rotating a fixed offset, and that is exact. A CUE HELD IN TWO HANDS IS NOT THAT. Its line comes from the two hand POSITIONS — grip through bridge — so turning your wrist does not move the tip at all, and rebuilding it as a rigid body on the butt controller would invent up to 1.5 m x omega of tip travel out of a turn of the wrist."

Accordingly CueVrRingCue carries a slide flag (cuevr_cue.c:1430–1439): rigid mode rotates a fixed offset, slide mode projects the hand's motion onto the locked line.

6.2 The 500 Hz pose ring versus the ~72 Hz frame

The problem statement is at mote_xr.h:30–43 and mote_xr.c:1159–1179: at 72 Hz a frame is 13.9 ms, which is 139 mm of tip travel at 10 m/s against a 52 mm ball. Before building a sampler thread, the authors measured whether extra samples would carry new information (MOTE_XR_TRACKPROBE, mote_xr.c:1180–1296), testing two things: how often the pose changes when polled at 500 Hz, and how far a sample sits off the chord joining its neighbours one frame either side. The answer is recorded in the header:

"Measured on a Quest Pro (2026-09-04), the runtime answers xrLocateSpace with GENUINELY NEW poses at about 480 Hz — 0.4% of samples 2 ms apart were collinear with their neighbours, where linear interpolation between 72 Hz updates would have made six in seven of them exactly collinear." (mote_xr.h:35–41)

The ring (mote_xr.c:1300–1368) is a detached pthread on a 2 ms nanosleep, writing both hands into a 1024-slot ring (~2 s). It is single-writer / many-reader: the head is published with a release store and read with an acquire load, the reader copies backwards and then re-reads the head to detect a lap (mote_xr.c:1354–1368).

Each sample carries the pose and the runtime's own velocity, chained onto the same xrLocateSpace call as an XrSpaceVelocity (mote_xr.c:1329–1344). The reason is a measurement of exactly the failure mode this avoids:

"A position stream can be smoothed — by the fusion, by the pose predictor, by anything between the sensors and us — and differencing a smoothed signal gives a smoothed speed with the peaks taken out of it. A cue delivery is nothing but a peak. Measured in a headset: a player swinging as hard as they could produced 12 mm of tip travel in 2.1 ms however hard they swung, and two very different strokes both scored 5.7 m/s." (mote_xr.h:47–61)

The tip's velocity from a sample is then v+ω×r in rigid mode, or the component of v along the locked line in slide mode (cuevr_cue.c:1464–1471).

hr_track() (cuevr_cue.c:1441–1549) consumes every ring sample newer than the last one taken, oldest first, and maintains two histories of length CUEVR_CUE_HIST=128 (cuevr.h:456–462): a filtered one (drawn) and a raw one (played). The filter is a single pole with the sample's own interval, k=1−e−Δt/τ, applied to the axis and to the across-line component of the tip's motion only:

Δt=Δ∥a^+Δ⊥,tsm+=Δ∥a^+k Δ⊥

(cuevr_cue.c:1482–1489). "MOVEMENT ALONG THE CUE IS NEVER FILTERED, at any setting. That is the delivery, and low-passing it would eat the power. Only the direction and the tip's movement ACROSS its own line are smoothed, which is the tremble" (cuevr_cue.c:1403–1405). τ∈{0, 15, 37.5, 75} ms (cuevr_cue.c:1973–1976).

A single filter running on the 500 Hz data is itself a fix: "This used to low-pass the FRAME's pose at frame rate while the strike walked the raw ring underneath it: two cues, and on the heavier settings they part company by as much as the filter's own lag the moment the stick moves. So the player aimed with one line and played the ball with another" (cuevr_cue.c:1954–1972).

Four tip speeds are recorded per frame (cuevr_cue.c:1493–1535): the per-sample rate, a 4-sample mean (hr_tipv_sm, "a single sample is mostly jitter"), a ~20 ms chord (hr_tipv20, immune to sampler jitter by construction), and the runtime-fused figure (hr_tipv_rt). The hand's own speed is kept alongside for diagnosis: "if the tip is barely moving faster than the controller, the cue is being carried rather than swung" (cuevr_cue.c:1512–1518).

6.3 Testing the tip's path against the ball across a frame

hr_contact() (cuevr_cue.c:1561–1602) walks the raw history — "The filter is for the eye: it shortens every step by the across-the-line part, so a stroke measured off it is measured short, and the power goes with it" (:1566–1569) — from the oldest sample not yet judged, testing each consecutive pair as a segment against the ball.

cuevr_seg_ball_hit() (cuevr_hit.c:4–25) is a segment–sphere test. With m=c−a, d^ the segment direction, L its length and ϱ=R+rtip:

along=m⋅d^,perp2=∥m∥2−along2,
reject if perp2>ϱ2,η=ϱ2−perp2,te=along−η,
reject if te>L or along+η<0,f=clamp⁡(te,0,L)/L.

The crossing yields the speed L/Δt, the hit point a+f(b−a), and the interpolated cue axis at that instant aa+f(ab−aa)^ — "The tip's PATH and the cue's AXIS are different things, and it is the axis the ball leaves along: a cue is a rod, so the impulse runs down the shaft" (cuevr_cue.c:1588–1593).

The ring's answer is subject to one sanity gate (hr_apply, cuevr_cue.c:1660–1667): it is discarded if it disagrees with the frame's axis by more than cos⁡−1(0.94)≈20°. "A pose ring is a lock-free ring written by another thread, and one torn sample would otherwise send a ball off at any angle it liked. Twenty degrees between the ring's line and the frame's is 1400 degrees a second at 72 Hz: no stroke does that. It is a guard against a bad read, not a limit on what a player may do."

The frame path is retained as a fallback and covers three cases, in cuevr_cue_update()'s tail:

  1. The line is on the ball (cuevr_cue.c:2840–3132): the frame's own geometry is computed from the axis–sphere chord, and the ring's answer overrides it when there was a crossing.
  2. The ball is behind the tip (along\_axis < -\varrho, cuevr_cue.c:2711–2779): ask the ring first, because at speed this is the aftermath of a strike rather than a shaft leaning on a ball. The measurement that forced this: "measured in a headset at a tip doing 7.07 m/s, the ball got 1.23, with no side, no screw and no elevation — the signature of this branch. The harder the stroke the likelier it is, which is why the top of the power range was both weak and unpredictable" (cuevr_cue.c:2712–2727). If the ring saw nothing, it really is a shaft push: speed is the closing rate of the perpendicular distance, capped at tip_v, with σ=τ=0 — "That is a foul, which is what it is on a real table, rather than a shot the player never played" (cuevr_cue.c:2698–2777).
  3. The line has already left the ball (cuevr_cue.c:2782–2838): the ring is the only answer there is, capped at 1.5× tip_v.

The whole reason the ring exists for the two-controller mode is stated with the number: "at 8 m/s it jumped 111 mm between looks and stepped straight over a 52 mm ball — 'the cuetip just goes through it and eventually side hits it'" (cuevr_cue.c:2631–2644).

6.4 Measuring the impact speed

Three estimators are computed and combined, in cuevr_cue.c:2884–3095.

(a) The gap history. gap is the axial distance from the tip's surface to the ball's, sampled once per frame into a 12-deep ring with cumulative times (CUEVR_SPEED_N=12, cuevr.h:255, cuevr_cue.c:2918–2925). The speed at contact is a three-point backward difference, exact for constant acceleration (cuevr_cue.c:2974–2996):

v≈−3g0+4g1−g22h,h=12(t0−t2SP), SP=2 frames,

used only when g2>g1>g0 (the whole span is forward motion), with a first-difference fallback otherwise. The motivation is a bias analysis:

"A trailing average — over the delivery, or over a fixed window — is biased low by however much the cue accelerated inside it, and that bias grows with the stroke: soft shots came out right and hard ones came out at three quarters. Every earlier test missed it because they all delivered at constant velocity, which has no acceleration to be biased by and measures identically over any baseline." (cuevr_cue.c:2959–2973)

An earlier design note explains why per-frame speeds are not averaged: "a predicted display time that lands a millisecond early, or a dropped frame that reports one interval's dt for two intervals' motion, and the same physical stroke reads as a tap or a smash" (cuevr_cue.c:2899–2917).

(b) The ring's crossing speed, from hr_contact (§6.3), capped at 1.5× tip_v.

(c) tip_v — a peak-tracking estimate of the tip's own speed (cuevr_cue.c:2677–2695), fed from the smoothed ring reading where available and from the drawn tip otherwise, held at the peak and decayed 0.8/0.2 toward the current value. "A real delivery accelerates, so an averaged speed lags the arrival and a ceiling built on it would dock power off exactly the hard shots."

The final reading is (c). cuevr_cue.c:3091–3093: sp = c->tip_v when available. The comment records the headset measurements that forced this and abandoned the gap as the primary reading (cuevr_cue.c:3061–3085):

"three deliveries of the same pace: ring 5.60 gap 23.18 over ONE frame -> the ceiling won -> 11.70; ring 5.35 gap 4.68 over four -> the gap won -> 6.05; ring 5.00 gap 5.34 over four -> the gap won -> 5.65. Twice the ball for the same stroke, decided by where the baseline fell. 'Sometimes going harder led to slower shots', reported."

Stroke gain. The measured tip speed is then remapped (stroke_gain, cuevr_cue.c:1645–1651):

f(v)={vv≤2.50v+0.256 (v−2.50)2v>2.50

This is an explicit, non-physical range remap, and the source says so and gives the fit data (cuevr_cue.c:1604–1644): a person in a headset spans "3.9 m/s at the tip for a gentle shot and 7.1 for everything they had", i.e. about 1.9:1, where the table wants 3:1 (a 4 m/s roll-up against a 12 m/s break). It is quadratic so the slope at the knee is exactly 1 "and there is no edge to feel going over it". The limits are stated honestly: "WHAT IT CANNOT DO is separate strokes that are the same. Four deliveries the player described as differently hard measured 4.70, 5.14, 5.19 and 5.45."

Firing condition (cuevr_cue.c:3056): rest_armed && speed_n >= 2 && gap <= 0 && speed > 0.12. A former glitch guard was removed at the player's instruction: "A break is exactly that shape — a still address, then everything at once — and at 12 m/s a frame is 167 mm, so a hold is a shot that fires late into the follow-through and a refusal is no shot at all" (cuevr_cue.c:3013–3022).

6.5 Tip contact offset and its mapping to spin

cuevr_strike_geom() (cuevr_hit.c:27–58) builds a frame from the cue axis and world up:

s^=y^×a^^  (fallback x^),u^=a^×s^^,o=h−c,
σ=clamp⁡ ⁣(o⋅s^ϱ,±1),τ=clamp⁡ ⁣(o⋅u^ϱ,±1),ε=arcsin⁡(−ay),

with the aim direction the flattened, normalised axis.

The divisor is ϱ=R+rtip, not R, and the consequence of getting it wrong is documented in detail (cuevr_cue.c:2851–2865): "off runs from the ball's centre to the point where the TIP's surface meets it, so its length is R + the tip's radius — and dividing that by R scaled every offset up by 19% … a merely off-centre contact gave the ball full spin and no speed at all — the tip visibly striking and the ball barely leaving." The tip radius is a player setting, quoted in millimetres across, with named presets: 8–9 mm English pool, 9.5–10 snooker, 11–12 carom, 12–13 US pool, 14 break cue (cuevr_app.c:10739–10751).

There is no miscue and no pace penalty for striking off centre (cuevr_cue.c:3117–3130): "There was a cliff here — past 0.55 of the radius the pace was cut to a flat 35% — and then a gentler version of the same idea. Both were wrong. Half a ball of side is an ordinary shot, and a hard step is a poor model of anything physical even where the effect is real."

(σ,τ,ε,d^) then go straight into cue_phys_strike_jump() (§1.6), where the offset is clamped to σmax=0.50 and converted to spin at ωR/v=2.5∣(σ,τ)∣.

6.6 Tip speed to ball speed

cuevr_app.c:22501–22512:

vball=vtip⋅Mcue(1+etip)Mcue+mball⏟transfer⋅ power_trim,vball≤12 m/s,

with Mcue=0.52 kg (18 oz) and etip=0.73 ("leather on phenolic"), cuevr_app.c:135–136, and MAX_STRIKE_SPEED = 12 m/s (cuevr_app.c:114). This is the one-dimensional elastic-collision result for a cue that is not slowed by the player's grip. The comment states the effect: "A cue is heavier than a ball (~0.55 kg against 0.16) and the contact is fairly elastic, so for a centre-ball hit the ball departs at roughly 1.35 times the tip's speed. Passing the tip speed straight through as the ball's — which is what it did — under-reads every shot by about a third."

power_trim is a player taste setting, 0.50–1.20, and the UI labels it as such: "The physics of tip-on-ball is not adjustable and is not what this is: it is how much of your arm's speed was you meaning it, and the honest answer depends on the room, the controller and the player" (cuevr_app.c:10752–10765, cuevr_cue.c:188–192).

Jump launch (cuevr_app.c:13375–13380):

vy=max⁡ ⁣(0, vballsin⁡(ε−εmin)⋅0.65−0.50).

It is a deadband, not a scale, and the reason is a physics-fidelity argument rather than a gameplay one: "a hop of a fraction of a millimetre would still suspend cloth friction for its whole flight, and cloth friction is where draw, follow and stun come from. Losing that intermittently, on an elevation difference nobody can see, would make every shot in the game feel unreliable" (cuevr_app.c:13345–13354). Subtracting rather than testing keeps it continuous. Notably, cue_phys_strike_jump requires the caller to compute vy, partly for this reason and partly for lockstep — "Two machines that each derive vy from their own reconstruction of min_elev can disagree about whether the ball left the bed at all, which is not a divergence any amount of position correction repairs" (cue_physics.h:646–662).


7. Numerical and architectural choices worth reporting

7.1 Fixed timestep and substepping

7.2 Determinism for networked lockstep

Online play is lockstep on the strike, not on the outcome: "Both machines integrate the same 2 kHz physics from the same state, so the same six numbers produce the same table on both sides" (cuevr_app.c:22608–22610). The wire packet carries direction, speed, side, vertical, elevation and the player's own squirt setting (cuevr_app.c:22612–22620). This places a hard bit-reproducibility requirement on the integrator, and three separate measures serve it.

(a) No platform libm in the hot path. cue_trig.h supplies cue_sincosf / cue_sinf / cue_cosf built from quadrant reduction plus Taylor cores to x9/x10, in double, rounded once — "ONLY + - * / AND CONVERSION, every one of which IEEE-754 rounds exactly, so the answer is a function of the input and nothing else." The reasoning is stated with its measurement:

"Two headsets run the same binary, so every arithmetic instruction agrees, but libm is part of the OS image: a Quest 2 and a Quest 3 are on different Android builds, and those are allowed to differ in the last place. A power shot amplifies a last-place difference by about a thousand — on a UK 8-ball break, moving the cue ball 100 nm moves the worst ball 0.001 mm at 2 m/s and 0.372 mm at 12, and a tenth of a millimetre in comes out a quarter of a METRE." (cue_trig.h:1–13)

The caveat is also stated: the compiler may contract a*b+c into an FMA differently between the arm64 device build and the x86-64 host, so host-to-device bit equality would need -ffp-contract=off; device-to-device equality is unaffected.

(b) The trig was removed algebraically where it could be. In cushion_impact the slip angles are never formed. The original took atan2f of each pair and immediately the cosine and sine of the answer; the replacement uses cos⁡φ=s(d)/r and sin⁡φ=s(n)/r with r already computed:

"Six libm calls a slice, 576 slices a cushion contact, to arrive back at the two numbers that went in. It is not only wasted work, it is the game's whole exposure to platform floating point … That is a Quest 2 and a Quest 3 disagreeing about whether a ball went down — reported from play, as 'only on power shots'." (cue_physics.c:823–844)

(c) No allocation in the per-shot record. The cue ball's contact log is a fixed CUE_MAX_TOUCH=24 array with an overflow flag, "because the match is lockstep, so this must fill identically on both machines with no allocation" (cue_physics.h:429–450).

The cush_sin/cush_cos storage decision (§0) belongs to the same family: "It was stored as radians, set with asinf() and read back with cosf() and sinf() in the same breath — a round trip through the platform's libm to recover the number that went in" (cue_physics.h:195–203).

7.3 Performance architecture

7.4 Deliberate departures from textbook physics

These are the places the source explicitly says it is not modelling the physics, and why.

Departure Where Stated reason
No pace penalty for an off-centre strike (no 1−offset2) cue_physics.c:388–401 "true of the impulse but wrong about the outcome" — a ball struck near its edge leaves at nearly the same speed
No miscue; the tip offset is clamped cue_physics.h:874–876, cuevr_cue.c:3117–3130 "These are good cues with chalk on them: a tip does not slide off"
Cushion lift above 2.5 m/s cue_physics.c:881–923 "This is EXTRAPOLATION, not measurement: nobody has published outgoing vertical velocities off a cushion"
Hop capped at 0.55 of the nose height cue_physics.c:910–921 measured: "at the uncapped value, four shots in a thousand ended up resting the wrong side of the cushion line"
Vertical spin from the rail scaled by κ=0.30; the linear friction impulse is not cue_physics.c:684–690 asymmetric on purpose: less new english, but incoming english still bends the bounce
Skittles topple rather than rebound the ball elastically cue_physics.h:452–467, cue_physics.c:1537–1547 "a ball that reaches one topples it and carries on, and pretending it is a post to rebound from would be a worse lie than ignoring the deflection"
stroke_gain remapping of human arm speed cuevr_cue.c:1604–1651 a person spans 1.9:1, the table needs 3:1
Jump launch is a deadband, not a scale cuevr_app.c:13345–13354 a sub-millimetre hop would suspend cloth friction and silently break draw/follow
The frame's top is a floor a ball can run along cue_physics.c:1870–1886, cue_physics.h:251–260 "Removing it the instant it passed the cushion line … deletes a shot that is still happening"
A ball off the cloth for 10 s is removed cue_physics.c:2400–2405 "a frame cannot wait on it"
iron_down caps the fall it produces at what the wall absorbed cue_physics.c:1387–1400 the naive form created energy; measured at up to 1.75 J/kg
Rolling on the pocket lip charges no extra energy for the rise cue_physics.c:2218–2226 the tangential gravity term already accounts for it
The AI does not adjudicate pots by simulation cue_ai.c:6089–6107 "letting a perfect simulation adjudicate it makes the opponent superhuman"

7.5 Two internal inconsistencies observed

Reported as read, without speculation about intent:

  1. collide_ball_ball splits the de-overlap equally (cue_physics.c:587–590) while its own comment says it splits by ball size.
  2. cue_phys_cut_out and cue_phys_drop_walls decide "middle pocket" from the index (p >= 4, cue_physics.c:1097, :1179) rather than from pocket_mid[], which the header introduces precisely because that index assumption fails on an L-shaped bed (cue_physics.h:343–348).

8. Appendix — the opponent's shot search (cue_ai.c)

Summarised for completeness; the full analysis is available separately.


9. The four things that are genuinely unusual

  1. The cushion is integrated over its own impulse, with two simultaneous contacts. Almost every billiards simulator resolves a rail as one instantaneous impulse against a tilted wall. This one implements Mathavan, Jackson & Parkin's scheme — 96 impulse slices, the slip direction free to rotate during the contact, energetic (Stronge) termination at W≤(1−e2)Wc — and, crucially, carries the cloth contact simultaneously with the cushion contact, which is what makes the ball's spin evolve correctly through the impact. The code cites Biber, Champneys & Szalai for why the single-impulse class cannot be fixed by tuning. On top of that, restitution is speed-dependent and per-table rubber (e=e0−keζ, floored), the contact height is recomputed per impact from the ball's actual altitude (so an airborne ball meets the nose below its centre and climbs), and the cloth's share of the impulse going negative is the physical trigger for the ball leaving the bed rather than a special case.

  2. The pocket is a signed distance field, and the same field is what you see. cue_phys_cut_out() gives the exact distance to an arc-with-two-tangent-legs cloth cut in closed form, with the piece selected by the signs of two local coordinates and no search. Its numerical gradient is the surface normal for the slate face; the same function decides where the cloth ends for the renderer, where the lip holds a ball, and whether a ball with no cloth under it is potted. Three concentric circles are kept deliberately distinct and deliberately reconciled — the drop/bore circle (capture, the hole in the floor, the jaw curve's terminus, the cushion-clipping circle), the cut circle (where slate ends), and the lip roll — and several of the file's most detailed comments are about failures caused by two of them drifting apart by millimetres. The lip itself is a genuine constraint with a leave-the-surface criterion vt2>gρcos⁡ϑ and rolling-without-slipping acceleration 57gsin⁡ϑ down it, so a firm pot flies off the crest and a dying one is carried round — behaviour that falls out of the model rather than being scripted.

  3. The strike is measured off a 500 Hz pose ring using the runtime's own fused velocity, not off differenced positions. The team measured, before building it, that the OpenXR runtime returns genuinely new poses at ~480 Hz (0.4% collinear at 2 ms, where interpolation would give six in seven), and then measured that differencing positions destroys exactly the peak a cue delivery consists of ("a player swinging as hard as they could produced 12 mm of tip travel in 2.1 ms however hard they swung, and two very different strokes both scored 5.7 m/s"). So the ring chains XrSpaceVelocity onto each xrLocateSpace, the tip's velocity is v+ω×r from the fusion, and the strike walks the tip's real 2 ms-resolved path as a sequence of segment–sphere tests — recovering the cue's axis at the sub-frame instant of contact, not just its path. The two cue modes reconstruct different things (rigid rotation of an offset vs a tip sliding on a locked line) because reconstructing a two-handed cue as a rigid body "would invent up to 1.5 m × ω of tip travel out of a turn of the wrist". A frame-rate strike test would step over a 52 mm ball at 8 m/s.

  4. Bit-level determinism is a first-class design constraint, and it visibly shaped the numerics. Because online play is lockstep on six numbers rather than on ball positions, the engine may not call the platform's libm: cue_trig.h is a from-scratch sin/cos using only exactly-rounded operations, the cushion solver's atan2/cos/sin were removed algebraically (576 libm calls per rail contact eliminated by recognising cos⁡(atan2⁡(n,d))=d/r), the cushion tilt is stored as a sine/cosine pair rather than an angle, and the per-shot contact log is a fixed array so nothing allocates. The sensitivity that forced this is quantified: on a UK 8-ball break, a 100 nm perturbation of the cue ball moves the worst ball 0.001 mm at 2 m/s and 0.372 mm at 12 m/s — "a tenth of a millimetre in comes out a quarter of a METRE", reported from play as two headsets disagreeing about whether a ball went down.

An honourable mention: the rigid-body solver's sphere-only "level support" sleep rule — a ball may sleep only when the exponentially-averaged total contact impulse (normal and friction) opposes gravity to within a quarter of a degree, a threshold derived from arctan⁡(57tan⁡T) rather than tuned — is a considerably more careful sleep criterion than a general-purpose engine usually carries, and exists because a ball at rest on a three-quarter-degree ball-return gully is otherwise indistinguishable from one coasting through zero on it.