Coordinates and spin-axis convention¶
pitchphys pins one spin-axis convention as the single source of truth, defined in pitchphys.coordinates. Every other module — the integrator, the force callables, the visualizers — reads from this convention. If you remember nothing else from this page, remember: clock-tilt direction = Magnus break direction under our convention.
World frame (right-handed)¶
x= horizontal, positive to the catcher's right (when looking from behind home plate toward the pitcher).y= forward, positive from release toward home plate. A pitch's initial velocity is mostly +y.z= vertical, positive up.
The plate sits at y = DEFAULT_PLATE_DISTANCE_M ≈ 16.76 m (55 ft) by default — that's the integrator's termination event.
Clock tilt (catcher view)¶
The clock face is viewed from behind home plate looking toward the pitcher. For a right-handed pitcher (RHP), the mapping from clock tilt to spin axis is:
| Clock tilt | Spin-axis vector | Magnus break direction |
|---|---|---|
| 12:00 | +x |
+z ("rise" — straight up) |
| 3:00 | -z |
+x (catcher's right) |
| 6:00 | -x |
-z (straight down) |
| 9:00 | +z |
-x (catcher's left) |
The mapping is a planar rotation in the catcher-view (x, z) plane:
Why "tilt = break direction" is intentional¶
For a pitch traveling along +y, the Magnus force is \(\mathbf{F}_M \propto \boldsymbol{\omega} \times \hat{\mathbf{v}}\). With \(\hat{\mathbf{v}} = +\hat{\mathbf{y}}\):
- Axis \(+\hat{\mathbf{x}}\) (12:00): \(\hat{\mathbf{x}} \times \hat{\mathbf{y}} = +\hat{\mathbf{z}}\) → break up ✓
- Axis \(-\hat{\mathbf{z}}\) (3:00): \(-\hat{\mathbf{z}} \times \hat{\mathbf{y}} = +\hat{\mathbf{x}}\) → break right ✓
- Axis \(-\hat{\mathbf{x}}\) (6:00): \(-\hat{\mathbf{x}} \times \hat{\mathbf{y}} = -\hat{\mathbf{z}}\) → break down ✓
- Axis \(+\hat{\mathbf{z}}\) (9:00): \(+\hat{\mathbf{z}} \times \hat{\mathbf{y}} = -\hat{\mathbf{x}}\) → break left ✓
It's a happy consequence of the right-hand rule. Under this convention, the clock-tilt number you specify is the direction the Magnus force pushes — you don't have to mentally compute a cross product to predict break direction.
RHP vs LHP¶
A LHP throwing the same pitch type as a RHP would have a mirrored spin axis. pitchphys handles this via the throwing_hand="L" argument:
PitchRelease.from_mph_rpm_axis(
speed_mph=95, spin_rpm=2400, tilt_clock=1.0,
throwing_hand="L", # mirrors the tilt across the 12–6 axis
)
Under the convention, throwing_hand="L" with tilt_clock=T produces the same axis as throwing_hand="R" with tilt_clock=12 - T. So a LHP at 1:00 maps to the same axis as an RHP at 11:00.
Spin axis vs movement direction¶
Pitfall — spin axis is NOT movement direction
A common confusion: the spin axis (the direction ω points) is not the same as the movement direction (the direction the ball breaks). They are perpendicular.
Example: a 12:00-tilt fastball has its spin axis pointing along +x (catcher's right), but the ball breaks up (+z). The Magnus force is 90° from the spin axis.
Statcast and many baseball-physics resources use multiple conventions interchangeably (catcher view vs pitcher view, clock-of-axis vs clock-of-break). pitchphys documents its single convention here and uses it consistently across the engine, the app, and the visualizations.
Active spin and gyro spin¶
The 3D pitch.spin_axis vector returned by PitchRelease mixes both active spin (perpendicular to velocity, drives Magnus) and gyro spin (parallel to velocity, drives nothing). The active_spin_fraction parameter on from_mph_rpm_axis splits them:
PitchRelease.from_mph_rpm_axis(
speed_mph=95, spin_rpm=2400, tilt_clock=12,
active_spin_fraction=0.95, # 95% of spin is active, 5% gyro
)
The internal decomposition lives in pitchphys.coordinates.decompose_omega(omega, v_hat). See Physics primer §4 for more.
Strike-zone constants¶
For visualization (and the "is it a strike?" indicator in the Streamlit app), pitchphys.coordinates exposes:
| Constant | Value | Meaning |
|---|---|---|
STRIKE_ZONE_TOP_FT |
3.5 |
Top of the rule-book strike zone |
STRIKE_ZONE_BOTTOM_FT |
1.5 |
Bottom of the rule-book strike zone |
STRIKE_ZONE_HALF_WIDTH_FT |
8.5/12 |
Half the plate width (17 in plate, half-width 8.5 in) |
These are educational approximations; real MLB strike-zone calls vary by hitter height.