accepted

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.

PassSonar default-behaviourbreaking-changechart-api

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/) uses round.angle = 1524 bins.
  • mplsoccer Pitch.sonar_grid defaults 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_LABELS in packages/react/src/compute/pass-sonar.ts become functions of the binCount input. PassSonarBinLabel widens from the current 8-label union into a generated label-per-bin scheme (or narrows to “direction only at cardinal/inter-cardinal ticks” when binCount > 8).
  • Ring direction labels on the renderer auto-skip to every N-th wedge when binCount > 8 so labels don’t overlap.
  • Static SVG fixtures for every PassSonar demo regenerate.
  • Keyboard arrow wrap uses model.wedges.length instead of hard-coded 8.
  • Pre-release change under the v0.2 break-contracts-outright policy (no deprecation shim).
← All decisions