accepted

PassSonar colour encoding is configurable; default is completion

`PassSonar` exposes `colorBy: "completion" | "distance" | "none"` with `"completion"` as the default. `"completion"` keeps the current attempted/completed annular stack. `"distance"` matches Eliot McKinley's canonical reference — bar colour encodes mean pass distance on a sequential ramp.

PassSonar default-behaviourchart-apivisual-encoding

Context

McKinley’s reference PassSonar (/Volumes/WQ/ref_code/PassSonar/) encodes:

  • Direction via wedge angle.
  • Frequency via bar length (linear-normalised to the max bin).
  • Mean pass distance via bar colour (viridis, clipped at 30 yards).

The v0.2 Campos PassSonar instead used two stacked annular wedges per bin (attempted + completed, different opacities) to encode completion rate. Distance survived only in the tooltip.

Both encodings are defensible and analytically distinct:

  • Completion-stacked → “where do this player’s passes break down?” (Useful for build-up analysis, defensive pressure reads.)
  • Distance-coloured → “how do this player’s passes combine direction and length?” (Useful for possession style, progression analysis.)

Without a colorBy prop the chart is effectively a different product under the same name as the McKinley reference, which confuses users who come to Campos expecting the canonical behaviour.

Decision

Add colorBy: "completion" | "distance" | "none" with "completion" as the default.

  • "completion" — current behaviour. Two annular wedges per bin: outer attempted (opacity 0.35), inner completed (opacity 0.85). Legend shows attempted / completed swatches.
  • "distance" — matches McKinley. Single wedge per bin, filled with a sequential colour ramp keyed off wedge.averageLength (Campos units, clipped at 30). Legend swaps to a gradient scale bar. Ignores wedge.completed for visual encoding (completion still surfaces in the tooltip rows and in the centre summary block).
  • "none" — single wedge per bin in seriesColors[0]. For consumers building their own derived encodings via the wedges render-prop.

Default stays on "completion" because that’s what Campos consumers have been reading for the last two versions; flipping the default would invalidate interpretation of every existing editorial chart that uses this component.

Why completion as default, not distance

  • The completion encoding is a stronger editorial read for the default audience (journalistic / analytical output focused on ball retention).
  • Distance-coloured is a specialist read; adding it as an opt-in means consumers who want the McKinley convention get it with one prop without forcing a visual-language shift on the rest of the ecosystem.
  • Matches the precedent set in /apps/site/src/content/decisions/shotmap-analytical-default-magma.md: the default is the one we tell newcomers is “safe to publish without thinking about it”.

Consequences

  • Compute layer gains averageLength as a first-class encoding input (already present on PassSonarWedgeModel as averageLength: number | null).
  • Renderer gains a distance-ramp legend mode and a sequential colour scale (probably sequentialRamp from the shared palette infra used by Heatmap / KDE, clipped at 30 Campos units to match the reference).
  • seriesColors prop still applies to "completion" and "none"; under "distance" it’s ignored in favour of a sequential ramp. A separate distanceScale?: SequentialScaleName prop will land with the distance implementation (out of scope for this decision doc — tracked in the PassSonar spec).
  • Tooltip rows are unchanged — direction / attempted / completed / completion / average distance always shown. No variant-specific conditional.
  • Empty state, warnings, summary block are unchanged.
← All decisions