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.
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 offwedge.averageLength(Campos units, clipped at 30). Legend swaps to a gradient scale bar. Ignoreswedge.completedfor visual encoding (completion still surfaces in the tooltip rows and in the centre summary block)."none"— single wedge per bin inseriesColors[0]. For consumers building their own derived encodings via thewedgesrender-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
averageLengthas a first-class encoding input (already present onPassSonarWedgeModelasaverageLength: number | null). - Renderer gains a distance-ramp legend mode and a sequential colour scale
(probably
sequentialRampfrom the shared palette infra used by Heatmap / KDE, clipped at 30 Campos units to match the reference). seriesColorsprop still applies to"completion"and"none"; under"distance"it’s ignored in favour of a sequential ramp. A separatedistanceScale?: SequentialScaleNameprop 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.