Pitch
Reusable football pitch surface for component authors: crop and orientation, pitch-space projection, theme and color overrides, grass patterns, tactical overlays, underlay layering, accessibility hooks, and export-safe SVG composition.
Interactive props.
Canonical behaviors.
Same crop, two outer SVG contracts. frame='crop' keeps the viewport tight to the focused half; frame='full' keeps a full-pitch viewport around the same cropped surface.
Half-pitch surfaces can be rendered left-to-right for components that scan horizontally or need a wide layout.
The left block is rendered through underlay, so the pitch lines sit on top of it. The right block is rendered in children, so it sits above the pitch lines.
Pitch is easy to retheme. Use the controller to preview the built-in presets and a custom color override without changing the component structure.
The interactive surface can host real popovers above the SVG. interactive=false removes that layer and leaves a clean export-safe snapshot.
Interactive story for built-in mowing patterns. Built-in object patterns are safe to document and serialize; function patterns need an export runtime that owns code execution.
Shared concerns.
Accessibility
Use role="img" and ariaLabel when Pitch is the standalone
surface. Higher-level chart components usually own the full chart label, legend, tooltip,
and keyboard semantics.
Responsive
The SVG fills the parent width and preserves the selected frame aspect ratio. Parent layout owns max width. Horizontal stories need wide containers; vertical surfaces scale cleanly into smaller cells.
Export
Pitch is deterministic SVG. Keep interactive={false} for export snapshots,
and avoid function-based grass patterns unless the export runtime explicitly supports
them.
Themeability
theme gives you a stable built-in preset. colors lets you
override fill, lines, and tactical markings directly, which is the right path for
brand palettes, blueprint treatments, and dark editorial surfaces.
Composition
Pitch owns only the surface. It does not own provider parsing, legends,
tooltips, headers, or chart card layout. Use underlay for background
surfaces and
children for foreground marks.
Normal, small, smallest.
Pitch-based charts scale fluidly to whatever width the parent gives them. The 'smallest' cell is sized for a 5×4 small-multiples grid (~140px wide). Vertical orientation only — horizontal pitches are too wide for small-multiples.
Best-practice examples.
Pitch
Minimal component-level usage for a pitch-based surface. Use children for foreground marks and add export/accessibility props at the surface boundary.
import { Pitch } from "@withqwerty/campos-stadia";
import type { PitchColors } from "@withqwerty/campos-stadia";
type EventPoint = {
id: string;
x: number;
y: number;
value: number;
};
const pitchColors: PitchColors = {
fill: "#17462a",
lines: "#ffffffd9",
markings: "#ffffff66",
};
export function AttackingHalfSurface({
events,
exportMode = false,
}: {
events: readonly EventPoint[];
exportMode?: boolean;
}) {
return (
<Pitch
crop="half"
attackingDirection="up"
side="attack"
frame="crop"
colors={pitchColors}
grass={{ type: "stripes", opacity: 0.35 }}
markings={{ halfSpaces: true, thirds: true }}
interactive={!exportMode}
role="img"
ariaLabel={`${events.length} attacking-half events`}
>
{({ project }) =>
events.map((event) => {
const point = project(event.x, event.y);
return (
<circle
key={event.id}
cx={point.x}
cy={point.y}
r={1.2 + event.value * 2}
fill="#f6c945"
stroke="#141414"
strokeWidth={0.25}
/>
);
})
}
</Pitch>
);
}
Public surface.
Primary pitch surface contract for pitch-based components, primitives, and static previews.
| Prop | Type | Default | Description |
|---|---|---|---|
crop | "full" | "half" | "penalty-area" | required | Visible pitch surface. Projection still maps the full Campos 0..100 pitch; the crop changes the viewport and rendered markings. |
orientation | "vertical" | "horizontal" | "vertical" | Pitch orientation. Vertical attacks upward; horizontal attacks rightward. |
side | "attack" | "defend" | "attack" | Visible end for cropped surfaces. Attack is top/right; defend is bottom/left. Ignored for crop='full'. |
frame | "crop" | "full" | "crop" | Outer SVG frame. Use crop for tight chart surfaces; use full to keep a full-pitch viewport around the selected crop. |
theme | "primary" | "secondary" | "primary" | Built-in pitch color preset. Colors override the selected preset. |
colors | PitchColors | - | Optional fill, line, and tactical-marking color overrides. Useful for team palettes, dark surfaces, and export frames. |
grass | GrassPattern | - | Optional mowing pattern beneath pitch lines. Built-in object patterns are SVG-safe; formula/custom function patterns need export-pipeline support before serializing. |
markings | PitchMarkingsConfig | - | Optional tactical overlays: half-spaces, thirds, 18-zone grid, or 20-zone positional-play grid. |
underlay | ({ project }) => ReactNode | - | Layer rendered after the pitch fill and before pitch lines. Use for heatmaps, density surfaces, territory zones, and other backgrounds. |
children | ({ project }) => ReactNode | required | Foreground SVG marks. The project callback maps Campos pitch coordinates to meter-scale SVG user units. |
padding | number | { top; right; bottom; left } | 0 | Extra viewBox breathing room, expressed as a percentage of pitch width. Use when large marks would clip near the boundary. |
interactive | boolean | true | Controls pointer events on the outer SVG. Set false for static export snapshots or when a parent owns interaction. |
role | string | - | Optional ARIA role on the outer SVG. Use role='img' for standalone surfaces. |
ariaLabel | string | - | Standalone SVG accessibility label. Higher-level chart components usually own the full chart label. |
Projection And Geometry Helpers
Framework-neutral helpers for pitch-space rendering and export tooling.
createPitchProjection(crop, orientation) Framework-neutral projection from Campos pitch coordinates to SVG meter units. Crop is accepted for API symmetry; projection always covers the full pitch.
computeViewBox(crop, orientation, side?, padding?) Returns the SVG viewport for full, half, and penalty-area pitch surfaces.
computePitchMarkings() Framework-neutral pitch geometry for non-React renderers. React consumers should prefer <Pitch>.
Create a React component using the Pitch primitive from @withqwerty/campos-stadia. Keep data fetching outside the component, use children or underlay for SVG layers, and include role='img', ariaLabel, and interactive={false} where the surface is standalone or export-oriented.