Primitive

Goal

Reusable goal-mouth surface for component authors: striker or goalkeeper perspective, goal-space projection, frame, net, and ground styling, theme and color overrides, accessibility hooks, and export-safe SVG composition.

Stories

Canonical behaviors.

Goal Component

Shot placement built directly on <Goal>. The Usage example below shows the component boundary; layer your own markers, legend, and surrounding chart UI outside the primitive.

Saved / blocked
Goal
xGOT scale
Goal Perspective

The same Goal shot map can be viewed from striker or goalkeeper perspective. The projection mirrors horizontally; the marker data and component usage stay the same.

facing="striker"
facing="goalkeeper"
Cross-cutting

Shared concerns.

Accessibility

Use role="img" and ariaLabel when Goal is the standalone surface. Higher-level chart components usually own the full chart label, legend, and surrounding explanatory text.

Sizing

Goal is much shallower than Pitch, so docs and chart containers should usually constrain width rather than stretching it across a very wide card.

Export

Goal is deterministic SVG. Keep interactive={false} for export snapshots or when a parent owns interaction.

Composition

Goal owns only the frame, ground line, net, and projection. Titles, legends, summary metrics, and provider parsing should stay outside the primitive.

Usage

Best-practice examples.

Goal

Goal-mouth surface usage. Keep provider parsing outside the component, set frame/net styling at the surface boundary, and project 0..100 goal-mouth coordinates inside the render prop.

                    import { Goal } from "@withqwerty/campos-stadia";

type GoalPoint = {
  id: string;
  goalMouthY: number;
  goalMouthZ: number;
  color: string;
};

export function GoalMouthSurface({
  shots,
  exportMode = false,
}: {
  shots: readonly GoalPoint[];
  exportMode?: boolean;
}) {
  return (
    <Goal
      facing="striker"
      interactive={!exportMode}
      role="img"
      ariaLabel="Goal-mouth placement"
    >
      {({ project }) =>
        shots.map((shot) => {
          const point = project(shot.goalMouthY, shot.goalMouthZ);
          return <circle key={shot.id} cx={point.x} cy={point.y} r={0.08} fill={shot.color} />;
        })
      }
    </Goal>
  );
}
                  
API

Public surface.

Goal-mouth surface contract for shot-placement and goalkeeping views.

Prop Type Default Description
facing "striker" | "goalkeeper" required Goal-mouth perspective. Striker keeps left post on screen-left; goalkeeper mirrors horizontally.
theme "primary" | "secondary" "primary" Built-in goal color preset. Colors override the selected preset.
colors GoalColors - Optional frame, net, ground, and background overrides for export frames, dark contexts, or editorial treatments.
netStyle "none" | "light" | "dense" "light" Net rendering density. none leaves just the frame and ground line.
netShape "flat" | "box" "box" Net geometry. box draws a recessed broadcast-style back frame and side panels inside the mouth.
netBackInset / netBackOffsetTop / netBackOffsetBottom number surface-scaled Controls recessed net depth and perspective when netShape='box'. Use these for broadcast-style 3D goal-mouth treatments.
netOpacity / netColumns / netRows number 0.45 / 8 / 4 Controls net visibility and grid density.
barThickness / netThickness / groundThickness number surface-scaled Independent stroke widths, in SVG user units. Changing bar thickness does not force net or ground thickness.
padding number | { top; right; bottom; left } 0 Extra viewBox breathing room, expressed as a percentage of goal width.
interactive / role / ariaLabel boolean / string / string true / - / - Static-export and standalone SVG accessibility hooks.
children ({ project }) => ReactNode required Foreground SVG marks. The project callback maps goal-mouth Y/Z 0..100 coordinates to meter-scale SVG user units.

Projection And Geometry Helpers

Framework-neutral helpers for goal-space rendering and export tooling.

createGoalProjection(facing)

Framework-neutral projection from goal-mouth Y/Z coordinates to SVG meter units.

computeViewBox("goal", "vertical", padding?)

Returns the SVG viewport for the goal frame.

computeGoalMarkings()

Framework-neutral goal geometry arrays for non-React renderers. React consumers should prefer <Goal>.

Use with AI
LLM Prompt
Create a React component using the Goal primitive from @withqwerty/campos-stadia. Keep provider parsing outside the component, project goal-mouth Y/Z coordinates inside the render prop, and include role='img', ariaLabel, and interactive={false} where the surface is standalone or export-oriented.