PassSonar defaults to 24 bins (15° wedges) instead of 8
`PassSonar` now defaults to `binCount: 24` (15° wedges), matching Eliot McKinley's canonical reference (`ref_code/PassSonar/`) and the convention adopted by mplsoccer / d3-soccer. Consumers that want the earlier 45° wedges must pass `binCount={8}` explicitly.
Context
The v0.2 PassSonar shipped with 8 wedges of 45° each. That’s coarser than every public reference:
- Eliot McKinley’s reference implementation (the canonical source, now in
/Volumes/WQ/ref_code/PassSonar/) usesround.angle = 15→ 24 bins. - mplsoccer
Pitch.sonar_griddefaults to 24 segments. - Ben Torvaney’s polar pass histograms (the antecedent work McKinley cites) use 12° / 15° bins.
At 45° wedges the chart can’t distinguish “forward” from “forward-right” — which is the analytical discrimination the sonar exists to surface. It also pulls the Campos output visually away from every published example a user might compare it against.
Decision
Make the bin count configurable with binCount: 8 | 12 | 24, defaulting to
24. Angular bins are centred on cardinal/inter-cardinal directions with
the forward bin straddling 0 rad on [-π/(binCount), +π/(binCount)).
Keyboard navigation wraps over model.wedges.length (deriving from the
model rather than hard-coding % 8).
Why configurable, not always-24
- 8-wedge sonars are genuinely useful in small multiples (squad grid, formation-overlay) where 24 wedges become illegible.
- 12 is a common middle ground (30° bins, aligns with clock positions and works well for mid-size cells).
- Defaulting to 24 matches the canonical convention; opting down is a deliberate act by the consumer.
Migration
- Want the previous 8-wedge output? Pass
binCount={8}. - Want the new canonical output? Do nothing.
- SmallMultiples / formation-overlay contexts should pass
binCount={8}or{12}explicitly based on cell size.
Consequences
BIN_COUNT,BIN_WIDTH,OFFSET,BIN_LABELSinpackages/react/src/compute/pass-sonar.tsbecome functions of thebinCountinput.PassSonarBinLabelwidens from the current 8-label union into a generated label-per-bin scheme (or narrows to “direction only at cardinal/inter-cardinal ticks” whenbinCount > 8).- Ring direction labels on the renderer auto-skip to every N-th wedge
when
binCount > 8so labels don’t overlap. - Static SVG fixtures for every PassSonar demo regenerate.
- Keyboard arrow wrap uses
model.wedges.lengthinstead of hard-coded 8. - Pre-release change under the v0.2 break-contracts-outright policy (no deprecation shim).