# Billiards Blueprint Physics Engine MVP v0.1.4
Physics validation report and integration plan · October 24, 2026

## Status
Functional standalone browser prototype. Numerical consistency checks pass; empirical real-table accuracy is NOT established. No existing applications or approved assessment geometry or scores were edited. Private deployment only.

## Model contract
One-dimensional, straight-in, horizontal shots with identical solid spheres. Radius R = 0.028575 m (2.25-inch diameter). Inertia I = 2mR²/5; mass cancels from this model. Gravity g = 9.81 m/s². Positive velocity points toward the object ball; positive angular velocity denotes forward roll. Distance control measures cue-ball center travel until first contact, not center-to-center separation.

Initial velocity is specified directly, not inferred from cue speed. Under an ideal horizontal impulse at signed height h, ω₀ = (5/2)(h/R)v₀/R. This ignores tip compliance, elevation, contact duration, cue effective mass, and miscues. Offset is now adjustable to ±0.80R for explicitly labeled idealized exploration. The ±0.50R dashed band denotes a typical miscue boundary; contact outside it is not presented as realistic reliable control. Even within it, successful grip is not guaranteed. The model assumes a successful horizontal impulse and cannot simulate miscues. Only vertical tip offsets are modeled; sidespin remains out of scope.

Contact slip u = v − Rω. During sliding, a = −μs g sign(u); α = (5μs g/2R) sign(u). Remaining slide duration is 2|u|/(7μs g). Each step integrates constant acceleration analytically and splits at the sliding-to-roll transition. Then v = Rω. Effective rolling resistance uses a = −μr g sign(v), maintaining ω = v/R and clamping at rest. This is an effective deceleration model, not a derived cloth deformation torque model.

At a frictionless head-on equal-mass collision with stationary object ball: vCB'=(1−e)vCB/2; vOB'=(1+e)vCB/2. Each ball keeps its own angular velocity. At e=1 translational momentum and kinetic energy are conserved and speed transfers entirely to the object ball. For e<1, kinetic energy decreases. Tangential ball friction and spin transfer are excluded. Cloth friction then converts retained cue-ball spin into draw/follow motion.

Defaults μs=.20, μr=.010, e=1 are illustrative assumptions, not fitted measurements. Runtime trajectory step is 1 ms; first contact is located by 35 bisection iterations within the crossing step. Display samples are 10 ms apart. Playback is sampled, not a continuously exact visual integration. A 0.65-second illustrative cue preparation precedes physical time zero. Cue follow-through is a time-stretched graphic over the first 0.28 simulation seconds, not a force or contact-duration calculation. Ball release in the inset uses a separate illustrative horizontal scale; dotted rotation remains driven by calculated angle. The ghost ball marks the starting contact location. Follow-through after separation does not change initial velocity or spin. Simulation now continues until both balls have zero translation and spin. The previous 12-second and display-boundary cutoffs are removed. A conservative parameter-derived safety guard remains; normal supported inputs terminate at rest. The top view fits the entire free-cloth path, with rest markers and a meter span. It is not a fixed-size physical table. No subsequent collision is modeled.

## Numerical checks actually run
Node test.cjs passed 13 checks (the original eight plus five v0.1.2 regressions):
1. Center-hit slide-to-roll speed and distance agree with analytic solution (vroll=5v₀/7).
2. Natural-roll deceleration and total stopping distance agree with v₀²/(2μr g).
3. Draw preset retains negative angular velocity at impact.
4. Follow preset retains positive angular velocity at impact.
5. Analytically selected stop offset yields zero impact spin within 10⁻⁶ rad/s.
6. Elastic equal-ball collision transfers forward speed (sample immediately after impact).
7. Low-speed long-distance shot stops before collision.
8. 30 combinations of offset, speed, and distance produce finite sampled states.

The UI stop offset rounds to .001R, so the preset is labeled Near stop rather than exact stop. Presets reset speed, distance and model coefficients; later slider changes do not force a named outcome. A center hit can become a follow shot after sufficient travel. The numerical tests are consistency checks and do not prove real-table accuracy. Conservation is supported analytically here; the current collision test checks sampled transfer, not a separate instantaneous energy assertion.

## Graphics and coaching
Light-blue felt and dark-gray rails are presentation assets. Table proportions, pocket marks and enlarged balls are schematic and do not replace approved BBPA geometry. The dotted cue-ball inset is a conceptual side-view rotation glyph driven by calculated angular displacement; it is not the appearance of topspin in an overhead camera.

Coaching text changes with sliding, rolling and post-impact context. Two connected-file searches did not find existing coach artwork. No substitute character was invented. window.BBCoachContext() exposes phase, explanation and a null characterAsset slot for later wiring. Actual character animation and identity mapping remain pending verified asset access.

## Real-table validation protocol — proposed, not performed
Use a measured level table, known ball diameter, clean matched balls, fixed camera and visible scale. Record cloth, ball set, humidity if available, cue elevation, setup distances, fps and uncertainty. Calibrate perspective before extracting positions. Use marked cue ball and high-frame-rate side footage to measure angular velocity independently of center motion.

First estimate rolling deceleration from several rolling-only trials and sliding friction from center-hit slide-to-roll trials. Separately measure collision restitution from incoming and outgoing translational velocities. Do not fit coefficients to the same shots used for holdout evaluation. Record delivered tip offset and initial speed, rather than relying only on intended values.

Run repeated center, low and high strikes over multiple distances and speeds. Compare x(t), v(t), ω(t), transition time, impact speed/spin, and post-contact displacement. Report MAE, spread and measurement uncertainty. Agree acceptance limits with Justin before asserting instructional prediction accuracy. Investigate residuals for elevation, cloth variation, spin loss, collision friction and boundary interactions. No validation thresholds or accuracy percentages are approved in this MVP.

## Integration plan — proposed
1. Keep physics.js as a pure standalone module with versioned inputs in SI units. Add richer event output and uncertainty before exposing predictions to production.
2. Add an adapter to the existing diagram renderer using its approved coordinates; do not alter table geometry to match this schematic stage.
3. Resolve approved character asset files, map sliding/rolling/impact context to coach IDs and approved scripts, and retain accessible text fallback.
4. Embed as an optional learning lab in coaching or Blueprint Play after review. No assessment score writes, Player Card rating updates, or claims of verification.
5. After holdout validation, consider drill setup guidance with explicit measured versus simulated provenance. Any assessment or scoring changes require separate approval and validation.
6. Add automated transition/collision event regression tests, timestep convergence checks, coefficient calibration profiles and browser/mobile QA before production integration. Then extend to cushions or cuts only under a new model version.

## v0.1.1 changes
Expanded vertical contact selector to ±0.80R, added tap/drag selection and a labeled typical contact band. Added cue shaft, ferrule, tip, selected surface contact, pre-shot stroke, release and follow-through to side view. Existing physics equations and assessment systems are unchanged.

## Sources informing the equations
- Dr. Dave, Cue Tip Height on CB (contact range and natural-roll offset): https://drdavepoolinfo.com/faq/cue-tip/height/
- Evan Kiefl, The physics of pool/billiards: https://ekiefl.github.io/2020/04/24/pooltool-theory/
- Ron Shepard, Amateur Physics for the Amateur Pool Player: https://www.sfbilliards.com/Misc/Shepard_apapp.pdf
- Princeton mechanics examples, billiard-ball motion: https://kirkmcd.princeton.edu/examples/ph205set4.pdf

The implementation is original; these references support the standard rigid-sphere mechanics. No proprietary drill graphics or assessment scoring were imported.

## v0.1.2 — complete stopping trajectories and distance predictions
The existing 1 ms analytic-within-step integrator runs to rest on unbounded cloth. Added exact path-length accumulation in each constant-acceleration segment, splitting at a velocity reversal so backward travel cannot cancel forward distance. Collision bisection restores pre-step distance before integrating to contact to avoid double counting. Cue total path, cue path after first contact, signed net post-contact position, object total path and time until both stop are reported. Units are meters and feet. Live distance readings and final-position markers use the same simulated states. Display sampling is 10 ms, plus an explicit final rest frame; timestamp lookup ensures playback reaches that final frame even when it falls between regular samples. 2× and 4× playback help with long trajectories.

Predictions assume unlimited flat cloth with the selected constant coefficients, successful grip, no cushion or pocket interaction, and one head-on collision. They may exceed real table dimensions and are not forecasts of a ball's position after real rail contacts. No real-table validation or scoring changes have been made.

### Additional v0.1.2 checks actually run
9. Forty-eight combinations spanning speed, tip offset, friction and restitution extremes finish with both balls at exactly zero velocity and spin; timestamp lookup selects the final rest frame.
10. Object-ball stopping distance matches the independent analytic slide-plus-roll formula within 10⁻⁷ m.
11. Draw travel sums forward and backward distance rather than cancelling them.
12. Constant-acceleration path integration correctly splits at a velocity reversal.
13. A long rolling shot continues beyond both the old 12-second cutoff and former display boundary and reaches rest.

## v0.1.3 display regression correction
The v0.1.2 full-path fit made setup distances visually shrink as predicted runout grew, and the previous side-view position was capped rather than camera-tracked. These were presentation defects, not proof of a change in friction or collision physics. Shot detail now uses a fixed 3.20 m viewport; Full travel is an explicit optional camera mode. A small overview always shows the full path, and off-screen position labels keep the main view honest. The enlarged side-view ball, starting ghost, cue and moving ruler now share a common world-to-camera transform, so draw reversals remain visible. The cue ball is never artificially clamped to a final visual position. Removed decorative pocket circles from the open-cloth view to avoid suggesting unmodeled pocket captures. Final coaching copy reports rest rather than continuing impact advice. Physics and predicted distances are unchanged.

## Bridge API 1.0 integration checks
A separate integration test host now mounts the same physics application through the supplied register/mount contract. Browser checks verified Draw and Follow selection, player/coach display context, forced Unverified status despite verified:true input, unmount during playback, and successful remount. Node boundary checks passed for existing-host registration, API-version rejection in the fallback registry, message origin/source filtering, forced unverified context, discarded extra properties and idempotent parent cleanup. The thirteen physics regressions still pass. Existing portal integration, external-origin authentication/framing behavior and existing character artwork remain unvalidated/unconnected. No assessment record or score writes were introduced.

## v0.1.4 — billiards stroke language and physical units
Launch speed is now entered in mph (0.5–37) and gap in whole inches (6–72). Exact conversion constants: 1 mph = 0.44704 m/s; 1 inch = 0.0254 m; 1 foot = 0.3048 m. The 37 mph limit is a user-selected launch-speed ceiling, not a claimed universal human speed record. The physics API rejects initial speeds above that ceiling. Spin is displayed in revolutions/second; signed linear quantities retain their sign. Internally all calculations remain SI.

Soft = 1.5 mph, Medium = 4 mph, Full = 7 mph are explicit illustrative preset choices, not measured definitions of Justin's strokes or standardized universal categories. Dr. Dave's typical-speed reference lists slow shots at 1–2 mph, medium at 2–4 mph, fast at 4–7 mph, power at 7–10 mph and powerful breaks at 25–30 mph: https://drdavepoolinfo.com/faq/speed/typical/ . Preset selection preserves gap, tip height and cloth settings; shot selection preserves stroke speed and dimensions. Stop setup computes required ideal offset from current conditions and flags impractical or unreachable setups.

Gap is measured edge-to-edge and equals cue center travel until collision; center-to-center separation adds the 2.25-inch ball diameter. Top view Shot detail draws balls at their physical diameter against a fixed 8-foot open-cloth lane (96-inch span), with a foot ruler. It is not an assessment table or approved table outline. Full travel uses minimum-size ball markers for visibility; magnified tracking side view remains explicitly illustrative in scale. Assessment geometry and scores remain untouched.

Optional rolling trial estimates μr = v²/(2gd) from a measured naturally rolling ball's initial speed and distance to rest, without cushions. Values outside the supported rolling-resistance range are rejected rather than clamped. The estimate is held only in the current app session. Sliding friction and restitution are not calibrated by this trial. A holdout trial is necessary before asserting predictive accuracy. Feet/inches rounding is presentation precision, not an accuracy claim.

### v0.1.4 regression checks
Sixteen numerical checks pass: the existing thirteen plus exact imperial conversion/ball dimensions, enforcement of the 37 mph initial-speed ceiling with completion to rest, and recovery of a known rolling coefficient from an independent analytic stopping distance. Bridge boundary checks continue to pass.

# v0.2.0 — table banking model (supersedes open-cloth limits for main app)
The previous straight-line model is preserved at straight-line.html with physics.js and app.js. The main application now uses table-physics.js and table-app.js. No assessment engine, geometry file, score or Player Card was edited.

## Geometry and source limits
Playing surface is 80 × 40 inches, balls are 2.25 inches, and the visual outer envelope is 94 × 54 inches. There are six diamonds on each long rail (at 10,20,30,50,60,70 inches) and three on each short rail (10,20,30), total 18. The optional grid includes the center through the side pockets. These numeric dimensions follow the established 7-foot template. The existing BBPA1000_Diagram_Engine_v1_2_Pilot.html was read: it explicitly calls its felt region image-relative and its cushion/pocket boundaries uncalibrated. Its raster artwork was not used as a collision mesh or modified.

Pocket cavities, mouths and jaws in this new view are schematic: the corner visual mouth uses an approximately 4.5-inch diagonal opening; side mouths use an assumed 5-inch opening. These are not recovered approved jaw curves, throat depths, cushion nose heights, or acceptance geometry. Do not use them to score assessments. Amber gates visibly close the mouths in banking mode. The collision boundary with gates closed is a rectangle at the cushion noses; there is no jaw collision model. Open-pockets mode uses approximate corner/side capture regions at a crossed cushion boundary, not a validated pocket simulator.

## Vector dynamics
Represent horizontal-axis spin by a two-component rolling-velocity vector q = R(ωy, −ωx). Contact slip is u = v − q. During sliding, dv/dt = −μs g û and dq/dt = +(5/2)μs g û. The analytic transition interval is 2|u|/(7μs g). At natural roll q=v, followed by constant rolling deceleration opposite velocity. Position uses constant-acceleration segment integration. Path length uses trapezoidal speed integration with a maximum 0.5 ms timestep, further limited to at most R/4 travel per step at initial speed. This is a numerical collision model, not an exact event-driven solver.

Ball contacts separate any small overlap along the normal and apply a frictionless equal-mass normal impulse J=(1+e)(vA−vB)·n/2 to approaching balls. Horizontal-axis spin is retained. Later contacts after rebounds are modeled. Cushion contacts clamp centers at one radius inside the rectangular nose boundaries and reverse/damp only the velocity component normal to the rail using eRail (default 0.75). Tangential velocity and horizontal-axis spin are retained; subsequent cloth friction acts on the new slip. This simplified frictionless-rail model excludes cushion height, compliance, tangential friction, sidespin, spin-transfer, throwback and speed-dependent restitution. It is not a Mathavan cushion model and has not been field validated. Ball restitution remains the prior user-adjustable value.

Default banking demo: Full example 7 mph, 24-inch initial surface gap, 0.75-inch cut offset, 12-degree aim direction, Follow tip height +0.40R, closed pocket gates. The cut is physical, not a cosmetic displacement. Input gap is Euclidean initial edge separation; cue travel to first contact differs slightly for a cut. Zero offset restores a straight-in setup; spin control on a cut does not remove all cue-ball tangent motion. Gap control is now limited to 6–60 inches so allowed setup directions fit on this table. All balls remain inside the table when gates are closed. Final distances sum the entire banked path; final position displacement is not substituted for travel.

The magnified dotted inset shows an instructional rotation using angular displacement projected on the original shot direction, not a complete 3D orientation reconstruction. The displayed spin number is projected on the original shot direction. It is explicitly conceptual after rail contacts; the top view is authoritative for translation.

## Numerical validation performed
Nine new table checks pass: (1) exact dimensions and ball diameter, (2) vector slide-to-roll against analytic straight case, (3) cushion normal reflection and energy loss, (4) oblique elastic equal-mass collision momentum/energy conservation, (5) default demo banks both balls and reaches rest, (6) closed-table containment and rest across soft/full/37 mph and draw/follow cases, (7) closed gate rebound versus open-pocket capture, (8) halving timestep keeps demo path totals within 0.02 m and rest time within 0.1 s, (9) 37 mph cap. The demo predicts two cue-ball rail hits and three object-ball rail hits with the default parameters. These are simulation results, not observed table measurements. The previous sixteen 1D/unit/calibration checks and bridge boundary checks also continue to pass.

## References for cushion assumptions
- Dr. Dave, approximate physical-property ranges (rail restitution 0.6–0.9): https://drdavepoolinfo.com/FAQ/physics/physical-properties/
- Dr. Dave, bank/kick physics effects and spin/angle limitations: https://drdavepoolinfo.com/faq/bank-kick/effects/
- Mathavan et al., A theoretical analysis of billiard ball dynamics under cushion impacts (not implemented here): https://journals.sagepub.com/doi/10.1243/09544062JMES1964

Next validation: measure rebound normal/tangent speeds and spin over approach angle and launch speed on the actual table; separately calibrate cloth; compare holdout bank sequences and stop positions. Approved pocket/jaw CAD or measured coordinates are still required for accurate jaw and pocket acceptance simulation.

## v0.2.1 — viewport layout
The main app is now a compact workspace with a small header, a viewport-height desktop simulation panel and independently scrollable shot controls. Canvas rendering fits the physical table uniformly to the available width and height; no physical dimensions or dynamics changed. The magnified cue-ball inset is more compact. Coaching, setup explanations, physics readings and reference material remain available in disclosures. Phone layout puts the simulation and playback first, followed by touch controls. Browser inspection covered the normal desktop viewport plus 900×700 and 390×844 iframe viewports. These are layout checks, not physical validation. The preserved straight-line page does not load the new workspace stylesheet.

## v0.2.2 — free placement and independent aim
The table engine now accepts optional positions: {cb:{x,y}, ob:{x,y}} in meters. Positions are copied into new simulation bodies, validated within cushion-center limits, and rejected if balls overlap. This path bypasses the generated 6–60-inch gap constraint because users can place balls anywhere within the table. Existing generated demo inputs remain supported. Shot direction independently sets the initial cue velocity and spin; it does not relocate either ball. First-contact draw/follow classification projects spin onto incoming cue velocity, including rail-first shots.

UI: drag either displayed ball with mouse or touch, drag the cyan direction handle, or tap empty felt to set the aim. Aim range is a full circle. Drag previews update without running a full trajectory on every pointer move; release recomputes the simulation. Dragged centers are clamped one radius inside the cushion and kept non-overlapping. Editing after playback can begin from the current displayed positions; Edit setup returns to the starting layout. Aim at object ball points toward its center to the angle control's resolution. Exact coordinate inputs in inches provide a keyboard-accessible alternative. Reset rail demo restores the prior banking layout. Old generated gap/offset controls are hidden in free-placement mode.

The compact layout, private access, bridge contract, approved assessment geometry and scores are unchanged. Three additional numerical checks pass: arbitrary positions with independent full-circle aiming and a true miss, rejection of overlap/out-of-bounds positions, and a legal custom diagonal layout beyond the generated-gap constraint. Twelve table-model checks now pass. Browser checks verified independent dragging of each ball, no position change when aiming directly at the object, and changing direction with the cyan handle. These do not establish real-table physics accuracy.

## v0.2.3 — reference equipment profile
The main app now explicitly identifies its reference setup as a Diamond 7-foot table with Simonis 860 cloth and Diamond rails, following Justin's equipment selection. The specific Diamond cushion generation/model has not been supplied. The numeric defaults are unchanged: sliding friction 0.20, effective rolling resistance 0.010 and cushion normal restitution 0.75. These are provisional simulation assumptions, not manufacturer-provided or measured product coefficients. No Diamond-specific bank-angle, spin-transfer or cushion-compliance model has been added.

Simonis's published standard 860 product data is 90% wool / 10% nylon and approximately 410 g/m²: https://iwansimonis.com/pool-cloth/ . The product data is stored as metadata and is not converted into friction. General equipment-property reference: https://drdavepoolinfo.com/FAQ/physics/physical-properties/ . The 0.75 rail coefficient is an illustrative choice, not verified Diamond data.

The equipment badge distinguishes reference defaults from adjusted coefficients. A Restore reference defaults button changes only the cloth friction and cushion restitution controls and clears the rolling-trial status; it preserves ball positions, aim, tip height, launch speed, ball-ball restitution, and pocket setting. Rolling calibration does not calibrate cushion rebound. Approved table dimensions, assessment scoring and verification boundaries remain unchanged.

## v0.2.4 — maximum launch speed reduced to 10 mph
Per Justin's instruction, both table and straight-line launch controls now end at 10 mph. Both simulation engines reject initial speeds above 10 mph (4.4704 m/s), and the rolling-trial speed input/helper use the same ceiling. Soft, Medium and Full examples remain 1.5, 4 and 7 mph. Prior 37 mph references above describe historical versions and are superseded by this change. Boundary and maximum-speed rest tests now exercise 10 and 10.1 mph. This is an initial launch-speed cap, not artificial clamping of calculated contact-slip velocity.

## v0.3.0 — Stun & shape planner (2026-10-25)

Implemented as `stun-planner.html` with `stun.css`, `stun-model.js` and `stun-planner.js`; accessible from the main lab header. Existing assessment projects are not edited or connected by this change. Existing stop/draw/follow free lab and bridge remain available.

### Solver and units

For approach travel d (cue-ball center displacement to first contact, not edge gap), launch speed v0, sliding friction mu_s, radius R, and solid-sphere inertia 2mR²/5:

- Impact speed vi = sqrt(v0² − 2 mu_s g d).
- Initial spin-surface speed q0 = (5/2) (h/R) v0.
- During drag q = q0 + (5/2)(v0 − v).
- Stun requires q = 0 at impact, giving h/R = −(1 − vi/v0).
- Ideal equal-mass, frictionless, elastic collision at cut angle a leaves cue-ball tangent speed vt = vi sin(a).
- With zero initial spin after contact, sliding distance = 12 vt²/(49 mu_s g), followed by rolling distance = 25 vt²/(98 mu_r g).
- Total unobstructed tangent travel S is the sum. Inverse solve: v0 = sqrt(S / [(12/(49 mu_s g)+25/(98 mu_r g)) sin²(a)] + 2 mu_s g d).

Ball launch speed remains capped at 10 mph. The solver rejects insufficient sliding speed, requests above 10 mph, and required |h/R| above 0.50. The 0.50 limit is an instructional guardrail, not a guarantee against miscues. Ball radius 28.575 mm; contact offsets are shown in mm and percentage of radius. Slider speed is rounded to 0.001 mph after inverse solving. UI readings may round further.

Stop selection uses a = 0, disables shape targeting and retains zero-spin arrival; target shape cannot be obtained along a tangent for a straight stop. Draw/follow remain in the free lab; inverse draw/follow and left/right English are not implemented here.

### Numerical verification

`node stun-test.cjs`: 11 grouped checks pass, including nine approach/cut combinations (6, 12, 24 inches by 15°, 30°, 60°), inverse/forward roundtrips, numerical spin at first impact within 0.025 rad/s of zero, analytic free tangent stopping distance versus isolated numerical sliding/rolling within 0.0000001 m, and eligible pre-cushion full-table distance agreement within 6 mm. Also checks speed/contact relationship, contact-limit rejection, unreachable shape and straight stop.

Planner calls existing table engine with dt = 0.0001 s and ideal ball restitution 1.00. Existing free lab's ball restitution control is not changed. All 16 prior straight-line/unit and 12 prior 2D checks pass; bridge tests pass. Numerical agreement validates consistency of the simplified equations and implementation, not real-table accuracy.

### Scope and limitations

A cyan marker shows the ideal unobstructed first-leg stopping position; it caps at the first cushion and warns if requested travel reaches a rail. Numerical white/gold trajectories include simplified rail rebounds and later collisions, so bank outcomes need not match the first-leg inverse target. The planner does not solve cushion shape, throw, sidespin, elevation, jump, cue compliance or tip/ball friction. Enlarged rear cue-ball graphic and decorative dots are conceptual; contact marker placement is calculated. Zero spin at impact is a target condition, not a real measurement.

Simonis 860 / Diamond rails coefficients remain provisional (mu_s .20, mu_r .010, rail .75). Friction can be adjusted in the planner independently of the free lab. Exact tip position and speed need table trials. No coach character assets were available; text fallback is explicit.

### Integration plan

1. Preserve these five static files plus `table-physics.js` as a standalone planner module. Use `stun-planner.html` as its entry point, or migrate its solver as a pure dependency-free module.
2. For the future app, prefer serving the planner under the same authenticated origin. A standalone iframe can load this entry point, but it does not implement the BBPAPhysicsBridge context handshake. Do not replace the working lab bridge with this page without adding and testing that protocol.
3. Existing private cross-origin authentication/embedding limitations remain unverified. No claim of completed BBPA assessment integration is made.
4. Add approved coach assets through the instructional layer after asset ownership and character mapping are supplied. Keep explanations separate from computed states.
5. Validate on the actual table using measured launch speed, approach distance, contact offset, zero-spin arrival and tangent stopping distance across multiple cut angles and repeated trials. Calibrate sliding and rolling friction separately; report errors rather than automatically fitting assessment scores.
6. Assessment scores, verification flags, Player Card records, approved assessment geometry and Blueprint Play stay outside this module. No storage or scoring writes are present.

Browser QA: target 24 in solved to a 4.055 mph launch with 13.7 mm low contact (rounded display); Full preset triggered the rail warning. Play reached 4.74 s / Rest in the default 4 mph trial, timeline 1000; replay/pause and straight-stop mode controls were exercised. A 390 × 844 iframe was visually checked for layout. No real-table trials were performed.

## v0.4.0 — Unified teaching engine and enlarged table (2026-10-25)

The main `index.html` now contains Manual spin, Stop, Draw, Follow and Stun / automatic tip modes on the same canvas. The separate stun interface has been removed; its old URL redirects to the main engine. The previous standalone UI JS/CSS are removed. The pure `stun-model.js` solver remains a shared dependency. The preserved 1D reference source and integration harness are retained for compatibility but are no longer linked as an alternate teaching engine.

### Ball placement and arbitrary aim

`shot-guide.js` computes the first cue-ball center intersection with a circle of radius 2R around the object ball, using current ball positions and shot direction. This yields the actual approach travel, impact normal, cut angle and tangent direction. It rejects misses, touching/overlapping initial contacts and cushion crossings before first contact. The same solver therefore works on mirrored and rotated cuts without moving either ball or changing aim.

Stun mode recalculates contact height as speed, position, aim or cloth coefficients change. It stays selected while the user drags either ball or changes aim. A manual tip edit explicitly switches to Manual spin. Invalid stun setups keep simulating the displayed manual contact, with a prominent no-match warning; they do not claim zero-spin arrival. No ball/aim is silently moved to manufacture a solution. Auto contact remains limited to 0.50R and the inverse model's supported 0–75° cut range. The warning includes the practical minimum speed for the current approach when geometry is valid.

Stop preset now uses actual direct-contact approach travel where geometry is available, rather than using the initial edge gap as though all cuts were straight. It explains that a cut with zero spin is stun rather than a straight stop. Default placement and banking setup are preserved.

### Teaching aids and larger surface

- The enlarged rear contact ball (154 px desktop / 164 px mobile) shares the main workspace, with mm contact height and an explicit auto/manual state. Decorative dots are conceptual; contact height is calculated.
- The optional ideal tangent overlay shows a ghost cue-ball contact position and a line perpendicular to the object-ball normal. Manual draw/follow paths can diverge from it. Cushion response, throw and sidespin remain outside that ideal tangent construction.
- Predicted full paths can be shown before play; live trails remain separate. Purple dashed center-hit comparison uses the same positions, aim, speed, friction and collision coefficients with only initial tip height changed to zero. It is a separate numerical trajectory, not a tolerance band.
- “At contact” pauses at the first stored frame at or after the first collision (up to the engine's ~0.01 s frame spacing). Contact spin text uses the actual pre-collision numerical reading.
- Inline shape solve updates speed and tip on the shared setup. It rejects targets beyond the first cushion, straight stop targets, unsupported contact heights and non-ideal ball restitution. It does not solve bank position. Green shape marker is an ideal first-leg reference, capped at the rail if needed.
- Cue side view is now optional and defaults off. This reduces its reserved canvas height from 114 px to 24 px. Compact readings give more height to the physical playing surface, while preserving its 2:1 aspect ratio and the unchanged 80 × 40 in dimensions. Desktop visual QA showed a substantially larger table using most available canvas width. Side view still shows the cue contact/follow-through teaching graphic when enabled.

### Verification

`guide-test.cjs`: 12 grouped geometry/physics checks pass. Ten rotated/mirrored 30° cuts (aims 0°, 45°, 90°, 180°, 270° on both sides) verify exact approach distance, perpendicular tangent, inverse shape, near-zero spin at contact within 0.025 rad/s, and on-table stopping distance agreement within 6 mm. Other checks reject misses and rail-first setups and identify a straight stop.

All 51 grouped numerical checks pass across `test.cjs` (16), `table-test.cjs` (12), `stun-test.cjs` (11), and `guide-test.cjs` (12). Bridge checks pass. Main UI syntax is checked.

Browser checks exercised Stun mode, speed changes and invalid-contact feedback; dragged cue-ball and object-ball positions while retaining Stun; tapped the table to adjust aim; solved a 12-inch target from an edited 9.6° cut (approximately 5.73 mph / 6.2 mm low in that trial); used center-hit comparison and At contact; and verified manual tip changes leave automatic mode. A 390 × 844 viewport iframe was visually checked with the table and Stun control functioning. No real-table accuracy claims or new coach assets are introduced.

### Integration

Keep `index.html`, `table-app.js`, `shot-guide.js`, `stun-model.js`, `table-physics.js`, `units.js`, `equipment.js`, `style.css`, `workspace.css`, `embed.js`, `bridge.js` and the retained required `physics.js` together. The existing bridge still mounts the main engine with stop/draw/follow context; its API and forced unverified boundary are unchanged. Stun is available as a UI mode after mounting, without changing the v1.0 host contract.

This update modifies only the physics Site. No separate assessment app integration has been completed or verified. Approved assessment geometry, scores, Player Cards, Blueprint Play and verification records are not modified. Coefficients remain provisional, and left/right English, throw, swerve and cushion friction/spin transfer remain unsupported.

## v0.4.1 — Maximize the actual playing surface (2026-10-25)

Layout/rendering change only; numerical physics and assessment specifications are unchanged. Shot modes, instructional state and equipment summary move to the adjacent control panel. Header, stage padding and playback readings are compacted to free space for the table itself.

The renderer now fits a viewport spanning the 80 × 40-inch playing surface plus a 3.8-inch margin on each side (87.6 × 47.6 inches total), rather than fitting the entire 94 × 54-inch cabinet plus padding. The outer cabinet continues to be drawn at its previous dimensions; only its far exterior is cropped by the viewport. All 18 diamonds, the playing boundary and schematic pockets stay visible. A uniform scale preserves the 2:1 playing-surface ratio, ball size relative to the table and pointer coordinate conversion. Side-view layout uses the fitted rail margin instead of the far cabinet edge.

Desktop visual QA confirmed the enlarged playing surface nearly fills the diagram width while retaining the adjacent contact ball and controls. Dragging at the new scale retained Stun mode and recalculated contact; the optional cue side view fit below the enlarged table. JavaScript syntax was checked. No change to equations, coefficients, scoring, bridge contract or assessment records; no new real-table validation is implied.

Responsive visual checks also passed at 900 × 700 and 390 × 844 viewport sizes; controls remain available alongside the table on desktop and beneath it on phone layouts.

## v0.5.0 — Object-ball rail response investigation and correction (2026-10-25)

### Finding

The previous cushion routine reversed/scaled normal translational velocity but preserved the entire incoming horizontal spin vector. For a naturally rolling object ball, that left excessive incoming roll after rebound. The subsequent cloth sliding calculation was internally consistent with that incorrect rebound state, producing an exaggerated bend and excessive normal braking. This is a shared cushion-model omission, not English deliberately transferred from the cue ball to the object ball.

A controlled comparison used an isolated rolling ball with incident velocity (-1, 0.5) m/s, matching rolling spin, restitution 0.75, sliding 0.20 and rolling 0.010. The old normal-only wall model changed heading by approximately 29.74° during post-rail slide. The revised model changed heading by approximately 14.40° in the same numerical experiment. These are model-to-model diagnostic values, not table measurements or proof of the exact correct bank angle. Some post-rail curvature is physically possible even without initial sidespin.

### Correction and assumptions

`railImpact` now integrates small normal impulse increments at an elevated cushion nose, with friction at the cushion and the supporting cloth. Each impulse updates translation, horizontal spin and vertical-axis spin. Coulomb impulses are capped at sticking, so spin is neither preserved blindly nor reset to outgoing natural roll. Reflection/rotation use the same law for both ball types; the cue-tip launch calibration and pre-rail sliding/rolling equations are unchanged.

This is a constrained impulse approximation with a prescribed effective horizontal normal restitution ratio. It is not a complete implementation of the energetic restitution/deformable-cushion model in Mathavan et al. The starting cushion-friction coefficient 0.14 is informed by their snooker fit; it is not measured Diamond data. The nose fraction is 0.635 of ball diameter, the WPA reference, not the paper's different 7R/5 nose assumption and not a confirmed measurement of the user's rails. Supported cushion friction is 0–0.25, avoiding negative supporting impulses within the supported 0.625–0.645 nose range. Vertical jumping is not modeled.

Rail-generated vertical spin is retained for later rail contacts and decays at a provisional 10 rad/s², within the broad literature range. Player-applied left/right English and ball-to-ball spin transfer remain unsupported. Pocket capture remains schematic. The effective rebound ratio 0.75 and friction values still need table calibration; the update does not make the engine manufacturer-certified or real-table validated.

Technical background:
- Mathavan, Jackson & Parkin (2010), *A theoretical analysis of billiard ball dynamics under cushion impacts*: https://drdavepoolinfo.com/physics_articles/Mathavan_IMechE_2010.pdf
- WPA equipment specification, cushion height: https://wpapool.com/wp-content/uploads/2024/01/RECOMMENDED-EQUIPMENT-SPECIFICATIONS.pdf
- Dr. Dave, bank/kick physics and real spin-dependent curvature: https://drdavepoolinfo.com/faq/bank-kick/effects/
- General spin-deceleration ranges: https://drdavepoolinfo.com/FAQ/physics/physical-properties/

### Object-ball-specific verification

`rail-test.cjs` adds seven grouped checks: straight rolling head-on rebounds at three speeds have exactly zero lateral translation/spin, retained incoming roll is reduced, reflection/rotation symmetry holds, 540 deterministic speed/spin/friction/restitution combinations remain finite and do not create total kinetic energy, 512/1024 impulse resolution converges within 0.002 in tested velocity/spin components, and full simulation records object-ball incoming/outgoing rail states and ends at rest. These checks verify implementation consistency and passivity, not measured bank accuracy.

All 51 prior numerical grouped checks still pass; the obsolete cushion test asserting unchanged spin/tangential velocity was replaced with an energy/spin-coupling check. Bridge checks pass. This gives 58 grouped numerical checks plus the 540-case energy sweep. First-contact stun and inverse travel checks are unchanged and pass.

The new “Object-ball rail check” action under Equipment & calibration sets a straight, zero-initial-sidespin reference: cue (12,20) inches, object (32,20) inches, aim 0°, launch 4 mph, auto stun, pockets closed. With reference coefficients, the object ball hits one rail, stays on Y = 20 inches with zero simulated lateral deviation, and the shot reaches rest at approximately 5.3093 s. Incoming object rail speed is about 0.7280 m/s and immediate outgoing speed is about 0.5460 m/s; its normal spin changes instead of remaining at full incoming roll. Rail events now expose both incoming and outgoing state for review.

No approved assessment geometry, score, Player Card or Blueprint Play records are changed. This corrects the shared rail calculation, so later cue-ball banks also use the coupled response; the investigation and added regressions explicitly focus on the object ball. Real-table video trials are still required before promising accurate Diamond bank angles or distances.

Browser QA loaded the new equipment controls, ran Object-ball rail check and verified the final timeline state at 5.31 s: both balls stopped and one rail hit. The large-table layout and existing placement controls remain intact.

## v0.5.1 — Continuous aim preview while held (2026-10-25)

Aim dragging now recalculates both numerical ball paths before pointer release. Input changes are coalesced into one calculation per animation frame through `live-preview.js`; each calculation reads the latest aim. The table keeps its prior rendered frame until the updated aim and trajectories can be drawn together, avoiding repeated blank-path flashes between pointer events. The cue and object ball remain in their starting positions during preview.

Stun mode stays selected while aiming and recalculates automatic tip height, approach travel, contact angle and predictions during the held gesture. The gold object-ball path, white cue-ball path, tangent reference and green ideal first-leg marker update together where valid. Misses and unsupported stun contacts continue to report no match rather than silently moving the balls. Live aim paths are shown while held even if the static Preview path checkbox is off; that preference still applies after release. Dragging a ball retains the existing release-to-recalculate behavior.

Pointer release commits the most recent aim. Pointer cancel, loss of capture and page exit cancel queued preview work, preventing stale callbacks from repainting a completed edit. Playback stays stopped during placement/aim editing. The physics equations, equipment coefficients, rail correction, table dimensions and assessment boundaries are unchanged.

Validation: `live-preview-test.cjs` checks latest-input coalescing, repeated held frames, one pending calculation per frame, cancellation and inactive guarding. `live-aim-test.cjs` executes the actual main application with pointer capture held in a deterministic DOM/canvas harness: repeated pointer moves update numerical direction, cut angle, auto tip and rendered path commands before pointerup; Stun remains selected; final release uses the latest aim and cancels pending work. It also checks live paths with the static preview toggle off. Both pass, along with main JS syntax and bridge checks. Browser drag smoke checks confirmed updated final angle, contact prediction and unchanged ball positions. Held-phase assertions come from the integration harness, not a real-device touch-latency measurement.

Integration adds `live-preview.js` before `table-app.js`; preserve that dependency in any source handoff. No approved assessment geometry, score or verification state is modified. Real-device performance across phone models remains unmeasured.

## v0.6.0 — Playable multi-ball Diamond Pro-Am practice table (2026-10-25)

### Reference and scope

Diamond's official Pro-Am page specifies a 7-foot model with an 80 × 40-inch playing area and a 94 × 54 × 32-inch assembled cabinet. Those existing dimensions are retained. Source: https://diamondbilliards.com/pages/pro-am . This page did not establish exact jaw angles, shelf depth or stock side-pocket mouth dimensions. All six mouths in this requested configuration are 4.5 inches; this is an explicit simulator configuration, not a claim that every factory Pro-Am side pocket is 4.5 inches. Ball diameter remains 2.25 inches and all 18 diamonds remain visible.

This is free practice and teaching, with up to 15 numbered object balls and one cue ball. It is not an 8-ball/9-ball rules referee: no turn, foul, scoring or verified Player Card logic is added.

### Shared physical pocket geometry

`pocket-table.js` defines the same mouth endpoints for rendering and collisions. Corner mouths span 4.5 inches diagonally (rail intercept 4.5/sqrt(2) inches); side mouths span 4.5 inches along the rail. Finite nose segments, short jaw segments and endpoint clearance account for the ball radius. A clean center crossing behind the mouth with radius clearance is captured; a lip contact resolves with the coupled rail impulse rather than being captured unconditionally.

Jaw depth (1.25 inches), jaw taper (0.25 inch at each end) and instantaneous mouth-plane drop are explicit approximations. Shelf/gravity, facing deformation, real pocket rattle/drop timing, cloth seams and Diamond machining tolerances have not been calibrated. Pocketing is functional and geometrically constrained, but acceptance at thin angles and high speed is not factory-accurate validation. Closed-pocket practice still uses the rectangular gated cushion boundary.

### Multi-ball physics and interaction

The engine accepts an explicit uniquely numbered `objects` array (IDs 1–15); all balls share the same translational, spin, cloth and cushion model. It resolves pairwise equal-ball contacts across the entire set with up to three local contact passes per step. This is a discrete approximation for simultaneous rack contacts, not a validated break-shot solver. Broad-phase coordinate checks and stationary-ball skipping limit preview cost. The 10 mph launch ceiling remains.

Frames and initial states now include `balls` arrays while retaining `cb` and selected-target `ob` aliases for existing consumers. Pocket events carry ball IDs and pocket IDs. First cue-ball impact records the actual contacted ID. The teaching geometry finds the nearest directly intersected ball, even when a different teaching target is selected; intervening balls are not ignored. Cue-only layouts are supported.

The picker adds/removes each numbered solid or stripe, rack-all loads 15 balls, and every selected ball can be dragged without overlap. The target selector controls direct Aim at object ball and exact target coordinates. Stun/live aim preview continues to use the first physically intersected ball. Colored preview paths and trails are available for all balls. Pocketed balls disappear from the cloth and enter the pocketed-ball ledger.

“Next shot” keeps the displayed positions, removes potted balls from the active layout, and preserves pocket history. A scratched cue ball is respotted at an unoccupied point and can be dragged for ball in hand. Rack/clear resets the ledger; selecting a potted number returns it to the table. Replay retains the last starting layout until Next shot is used. A fresh page load does not persist a game.

### Validation

`pool-test.cjs` adds eight grouped checks: all six measured mouth widths; potting into all six pockets; closed gates; jaw-first lip contact; cue-only scratch; a 15-ball rack with finite identities/positions, energy passivity, multiple collisions and final rest; first-ball teaching geometry independent of selected target; and rejection of duplicate/invalid/overlapping objects. All pass. Rack timing in this container was approximately 66–102 ms per full 7 mph prediction; this is not a phone performance measurement.

The actual-application DOM/pointer harness also passes numbered selection/removal, rack setup, ball-8 pocketing, ledger retention, next-shot continuation, switching an empty table to manual control, and scratch respot. The existing live aim, held-pointer, rail, geometry, stun, unit and bridge checks pass. In total, 66 numerical check groups pass (58 previous + 8 new), plus UI, live-preview and bridge checks.

Browser QA selected ball 8, set cue (40,28) and ball 8 (40,14) inches, aimed -90°, used 4 mph Stun and inspected the end frame: ball 8 pocketed in the top side, no rail hits, remaining cue at rest. Next shot removed 8 from the layout, preserved its ledger entry and kept the cue at approximately (40,16.249) inches. The full 15-ball rack was visually checked with numbered solids/stripes.

### Preservation and integration

`pocket-table.js` is now a required shared dependency before `table-physics.js`, alongside the prior engine files. Existing single-object parameter calls remain supported. Approved BBPA assessment projects, assessment geometry and scores are not edited. BBPAPhysicsBridge remains API v1.0 with forced unverified context; no results are written to assessment records. Real-table cloth, rail and pocket validation is still outstanding.

## v0.7.0 — directional English and rail teaching lab

The existing table now accepts a rear-view radial contact `(side, tip)` in units of ball radius. Positive side is the shooter's right and positive tip is above center. Combined contact is capped at `sqrt(side²+tip²) <= 0.80`; the 0.50R dashed circle is a typical practical contact boundary, not a guaranteed miscue predictor. Values beyond it are explicitly idealized exploration. For a level cue, prescribed ball launch speed `v` and solid-sphere inertia `I=2mR²/5`, the impulse gives horizontal rolling-spin vector `q = 2.5 * tip * v_direction` and vertical spin surface velocity `sz = Rωz = -2.5 * side * v`. Launch speed is held fixed; this does not solve cue speed, tip grip, cue deflection or miscue probability.

Vertical spin decays at configurable constant angular deceleration (default 10 rad/s², provisional, range 1–30 in the UI). Its sign cannot overshoot zero. Integrated yaw is used only as a conceptual dotted rotation cue; the display is not a reconstructed 3D sphere orientation. The existing coupled cushion/cloth impulse model receives the full spin state at every rail and jaw. No artificial sideways force is added during free travel. Object balls start without applied sidespin; normal equal-ball collisions retain each ball's spin and do not transfer English or calculate spin-induced throw.

The large cue-ball selector supports simultaneous high/low and left/right drag; both axes also have keyboard sliders. A radial limit replaces the former vertical-only contact band. Stun auto mode cancels approach forward/back spin while retaining selected sidespin; it does not mean zero total angular velocity. Conventional Stop/Draw/Follow presets clear sidespin. The comparison retains height, speed and layout and sets only side to zero. Rail English lab builds a cue-only angled shot with pockets closed, and At cue rail pauses at the first stored frame after cushion contact. The rail readout reports incidence/rebound angles from the normal of the last impulse (jaw/corner contacts can comprise several impulses), incoming/outgoing vertical spin and running/check classification by incoming spin direction relative to along-rail motion. Signed spin follows table x-right/y-down coordinates. Running/check labels describe relative direction, not a guarantee of a particular rebound angle.

Verification: existing 66 grouped numerical checks and 540 passive rail cases pass; live-aim, pool UI and bridge checks pass. New `english-test.cjs` checks torque and sign, unchanged pre-cushion direction for a level-cue shot, correct head-on side kick, mirrored trajectories, running/check parallel-speed ordering, exact spin decay/yaw integration, radial/input validation and complete rest. An additional 135 cushion cases with nonzero applied sidespin show finite states and no total energy gain. Actual application pointer tests cover combined held contact, radial clipping, rail inspection, no-side comparison, centering, Stun side retention and conventional preset reset. These are numerical/implementation checks, not real-table accuracy measurements.

Teaching reference: [Dr. Dave — sidespin terminology and uses](https://drdavepoolinfo.com/faq/sidespin/terminology-and-uses/) and [squirt, swerve and throw](https://drdavepoolinfo.com/FAQ/sidespin/aim/effects/). These explain the effects omitted from the level-cue launch model. Cushion formulation remains the constrained impulse approximation documented in v0.5.0, not a manufacturer-specific validated solver.

Validation still required: record measured launch speed, spin rate, incidence angle, outgoing angle/speed and spin across multiple speeds, tip offsets and cloth conditions on the intended Diamond table. Fit spin decay independently on cloth, then cushion friction/restitution against rail data. Reserve independent shots for error reporting. Squirt requires cue-specific data; swerve/masse require cue elevation and a 3D contact/cloth model; throw requires ball-ball friction. None of those effects is represented as calculated in this release. Assessment geometry, approved scores, Player Cards and bridge verification behavior are unchanged.

## v0.7.1 — geometry and rail validity review

The v0.7.0 tests established implementation consistency, not real-table accuracy. This review does **not** certify Diamond rebound angles or pocket behavior.

Confirmed geometry: the official Diamond Pro-Am specification gives a 7-foot playing surface of 80 × 40 inches and cabinet of 94 × 54 inches. The canvas uses one scale factor on both axes, 2.25-inch balls, and 18 reference diamonds. Cabinet clipping is solely for viewport fit. The six 4.5-inch mouths are the requested configuration; actual side-mouth size, jaw angles, shelf and facing dimensions have not been measured. This is a dimensioned schematic, not a factory-machining template, and approved assessment geometry is untouched.

A real rendering inconsistency was found: black circles were painted beyond the shared jaw/throat polygons without matching collision surfaces. Those decorative circles are removed. Mouth/jaw rendering now uses the same endpoints as collision geometry. A rounded black back to each cavity is drawn entirely beyond the capture plane; it is a conceptual already-captured area, not an additional collision boundary. Capture still occurs at a simplified mouth plane: pocket shelf/drop timing and rattles remain approximate. Rail contact uses a 2D sphere footprint (radius R), not an exact 3D nose-contact projection. At nose height 0.635D the projected offset would be about 0.963R; this approximately 1.06 mm distinction is retained as a documented 2D contact approximation rather than misrepresented as exact geometry.

The prior solver forced the outgoing horizontal normal speed to `e × incoming normal speed`, even while spin/friction exchanged energy. It is replaced with a work-based compression/restitution integration: normal compression work is accumulated until normal approach speed reaches zero, then recovery ends at `e² × compression work`. Coulomb cushion and supporting-cloth impulses continue to update all spin components and translation. Input 0.75 now denotes an **energetic** coefficient and is not equivalent to the previous speed-ratio setting. It remains an uncalibrated reference value. This is a constrained point-contact approximation with regularized sticking, not a complete rubber deformation or validated Mathavan implementation.

Sources for that distinction: [Mathavan, Jackson & Parkin (2010)](https://drdavepoolinfo.com/physics_articles/Mathavan_IMechE_2010.pdf), especially equations 16a–c. Its fitted 0.98/0.14 values came from a snooker setup with a different nose-height assumption; they are not Diamond constants. The paper's reported average 0.818 head-on rebound ratio has **not** been reproduced as an independent quantitative benchmark here. A local diagnostic at its nominal 0.70D nose, 0.212 cloth friction and 0.98 energy restitution gives approximately 0.911 in this constrained/regularized variant. That discrepancy prevents a claim that this solver is a validated reproduction of the paper, let alone of a Diamond table. Do not present it as one.

Readout clarification: immediate rebound angle and isolated post-sliding angle are now separate. The latter advances an isolated ball through its slip-to-roll transition with no intervening collision; it is a reference direction, not a guaranteed next-rail angle. Top-view dots now rotate with vertical-axis spin only; forward-roll projection is no longer added to their planar rotation, which previously made roll look like sidespin. Roll orientation is not reconstructed. Contact defaults to a radial 0.50R cap; 0.80R requires an explicit idealized-exploration checkbox. Unachievable combined auto-stun contact is reported as unmatched.

Checks cover the analytic frictionless rebound limit, recovered/compression-work ratio, passive total energy over 540 prior and 135 English cases, sign and mirror symmetry, numerical convergence, complete rest, multi-ball/pocket regressions, live aim, two-axis input and the default radial cap. The old assertions requiring an exact normal-speed ratio were replaced because that assumption was deliberately removed; the unchanged frictionless analytic limit remains independently tested. Passing these checks does not close the quantitative-validation gap above.

Required calibration/acceptance: measure actual table pocket cuts and cushion nose; record naturally rolling no-side, stun, draw and combined-side shots at measured approach speeds and angles. Compare immediate and settled trajectories separately; then fit cushion/friction parameters and report held-out trajectory errors. No such footage or measured trial data has been supplied for this release. Until then, use the app for qualitative exploration, not precise bank aiming or verified assessment scoring.

Other references: [Diamond Pro-Am dimensions](https://diamondbilliards.com/pages/pro-am), [Dr. Dave's bank/kick effects](https://drdavepoolinfo.com/faq/bank-kick/effects/). Those effects include real post-cushion curvature and differences between equipment; a simple mirror reflection is not a general correctness test.

## v0.8.0 — realistic and ideal ball-contact modes

This revision replaces the main application's frictionless ball-contact default with a planar frictional, inelastic equal-sphere impulse. **Realistic Teaching** mode defaults to ball restitution `e = 0.94` and the speed-dependent Alciatore TP A-14 friction fit `μ = 0.01 + 0.10 exp(-0.98 v)`, where `v` is relative tangential surface speed in mph. **Ideal Geometry** mode deliberately uses `e = 1` and `μ = 0` so students can compare the textbook tangent construction with the modeled non-ideal result. The direct `collide()` API remains frictionless unless a friction option is explicitly supplied for backward compatibility.

For a horizontal contact normal `n` and tangent `t`, the relative tangential surface speed includes translational slip and both balls' vertical-axis spin. The tangential impulse is capped by both Coulomb friction and the identical-solid-sphere no-slip value `|Jt| <= |u_t|/7`. It updates both balls' translational velocity and vertical-axis spin. This produces cut-induced throw, spin-induced throw and transferred object-ball side spin, which are then carried into later cloth and cushion interactions. The event record exposes normal/tangential impulses, fitted friction, relative surface speed, object-ball throw, transferred spin and post-contact path separation.

This is still a **2D planar collision approximation**, not Pooltool's complete Mathavan 2014 model. It does not calculate the vertical contact component, ball compression duration, simultaneous table impulse during contact, hop, cue squirt or swerve. The Alciatore friction curve and `e = 0.94` are literature reference values, not measurements of the user's ball set. Diamond cushion and pocket calibration remains outstanding. Accordingly, the new output is a stronger physical teaching estimate but is not yet a validated prediction for a specific real table.

The interface now shows the active model and reports object-ball throw, transferred side spin and post-contact path separation for first cue-ball contact. Older sections of this report describe the historical frictionless releases and are superseded by this section for the main v0.8.0 application. The assessment application, approved assessment geometry, scores, Player Cards, Blueprint Play and bridge verification boundary remain unchanged.

The Stun shape tool now has two deliberately different solvers. Ideal Geometry retains the closed-form frictionless tangent-distance solution. Realistic Teaching numerically searches launch speeds from 0.5–10 mph, recomputes the low-tip stun contact at each candidate, and evaluates the full collision simulation until rest or the first cue-ball rail. It requires exactly one object ball and rejects targets beyond the first rail or contacts beyond the selected radial limit. A browser QA case matched a requested 12-inch first leg at approximately 4.33 mph and 11.4 mm low for the default 19.5° cut; this is a simulator result, not real-table validation.
