accepted

`autoPitchLines` overrides user `pitchColors.lines` on dark ramps — the only prop that breaks user-wins

When `autoPitchLines: true` (default) and the colour ramp is dark (magma, inferno, viridis, or a custom dark gradient), pitch lines are forced to white — even if the user passed `pitchColors.lines="#333"`. Dark ramp + dark lines makes the pitch disappear; legibility wins over API consistency.

HeatmapKDETerritory default-behaviourvisual-encodingaccessibility

Context

Campos generally honours the “user prop wins” precedent: if a consumer passes a value, the library uses it as given. autoPitchLines is the one place that rule doesn’t hold. Dark colour ramps over a pitch render the halfway line, penalty boxes, and centre circle invisible if the theme’s default pitch-line colour is dark grey. That’s an instant legibility failure on any broadcast or editorial surface, and opt-in defaults would mean every Heatmap consumer had to manually pair their ramp with a light pitch-line colour.

Decision

autoPitchLines defaults to true on Heatmap, KDE, and Territory. When it’s on and the resolved colour ramp’s low-end is below a luminance threshold, pitchColors.lines is forced to white in the rendered output — user value ignored. Set autoPitchLines: false to respect user pitchColors unchanged.

Why override instead of warn

The cost of a surprise-override is a small API inconsistency. The cost of respecting the user here is that every dark-ramp heatmap looks broken until the user notices. That’s the wrong trade for a default-publishable library. Consumers who need the user-wins rule turn the auto-override off with one prop.

Consequences

  • Docs call this out explicitly as the single exception to the prop-precedence rule, and the prop name autoPitchLines encodes the escape hatch.
  • Dark-ramp heatmaps are publishable with zero config.
  • Light-ramp heatmaps pass through user-supplied pitch-line colour unchanged — the override is conditional, not unconditional.
  • New pitch-anchored density components should evaluate this pattern for adoption; it’s deliberately narrow in scope right now.
← All decisions