import type { StreetNetwork, StreetVec2 } from "./streetGenerator.js"; /** How a sealed-off side street is closed: hard barriers, a cone line, or temporary fencing. */ export type CircuitSealKind = "barrier" | "cones" | "fence"; /** Fully-defaulted sliders the route search answers to. */ export interface CircuitRouteRules { seed: string; /** Target lap length in meters — the search keeps the cycle closest to this. */ lapLength: number; /** 0 races any street; 1 keeps the lap on avenues and boulevards only. */ arterialBias: number; /** * Radius (m) the corner-rounding pass works the racing line toward. Bounded by `cornerCut` and the * road width — the line never leaves the street — so the achieved figure is reported back as * {@link CircuitRoute.tightestRadius} rather than enforced here. */ minCornerRadius: number; /** Ordered checkpoint gates placed around the lap. */ checkpoints: number; /** Laps the produced race runs. */ laps: number; /** Half-height of a checkpoint gate volume (m) — how tall the trigger box reaches. */ gateHeight: number; /** Starting grid slots behind the line (0 = no grid). */ gridSlots: number; /** How the side streets leaving the lap are closed off. */ sealKind: CircuitSealKind; /** Timing sectors the lap splits into. */ sectors: number; /** * Arc-length spacing (m) the lap is resampled to. City streets are sampled coarsely enough for a * road ribbon but far too coarsely for a racing surface, corner analysis, or kerbs. */ sampleStep: number; /** * How far the racing line may be pulled off the street centerline while rounding a junction, as a * fraction of the local half-width. 0 keeps the hard kink; ~0.5 uses the full lane either side. */ cornerCut: number; } /** Defaults: a ~2.4 km arterial street lap with 12 gates, 3 laps, and barriered side streets. */ export declare const CIRCUIT_ROUTE_DEFAULTS: CircuitRouteRules; /** * One street closed off where it leaves the lap — the thing that turns public roads into an * instanced event. Stands just off the junction, spanning the sealed street's full width. */ export interface CircuitSeal { /** Volume-local XZ of the barrier run's center. */ x: number; z: number; /** Yaw (radians) pointing down the sealed street, away from the lap. */ heading: number; /** Width of the street being closed — the run spans it plus a shoulder. */ width: number; kind: CircuitSealKind; /** Graph node the seal stands at. */ node: number; } /** One analyzed corner: where the lap turns, how hard, and which way. */ export interface CircuitCorner { /** `centerline` index at the apex (tightest point). */ apex: number; /** Radius of curvature at the apex, meters. */ radius: number; /** Total turn through the corner, radians. */ angle: number; /** -1 = left-hand, 1 = right-hand. */ direction: -1 | 1; /** `centerline` index where the corner starts. */ entry: number; /** `centerline` index where it ends. */ exit: number; } /** One checkpoint trigger volume, shaped to hand straight to `raceTrack({ checkpoints })`. */ export interface CircuitGate { id: string; center: readonly [number, number, number]; half: readonly [number, number, number]; } /** The start/finish line: where it is, which way cars face, and the painted line across the road. */ export interface CircuitStart { x: number; z: number; /** Yaw cars face on the grid (direction of travel). */ heading: number; /** The two road-edge ends of the painted line. */ line: readonly [StreetVec2, StreetVec2]; /** Arc-length position of the line along the lap, meters. */ distance: number; /** Road width at the line. */ width: number; } /** One grid slot: a staggered spawn behind the start line. */ export interface CircuitGridSlot { x: number; z: number; /** Yaw facing down the start straight. */ heading: number; } /** One kerb strip on the outside or inside of a corner, as an offset polyline to stripe. */ export interface CircuitKerb { /** Polyline along the road edge the kerb hugs. */ points: StreetVec2[]; /** Strip width across, meters. */ width: number; /** Which side of travel the strip sits on: -1 left, 1 right. */ side: -1 | 1; /** Alternating stripe length along the run, meters. */ stripe: number; /** Corner this kerb belongs to (index into {@link CircuitRoute.corners}). */ corner: number; } /** A closed race lap lifted out of a street network, with everything a race needs hung off it. */ export interface CircuitRoute { /** Closed lap centerline in volume-local XZ. Implicitly closed: the last point joins the first. */ centerline: StreetVec2[]; /** Road width at each centerline point, inherited from the streets the lap follows. */ widths: number[]; /** Road-surface height per point, present only when the network carries elevation. */ heights?: number[]; /** Lap length, meters. */ length: number; /** Graph edge ids the lap runs on — style exactly these streets as track surface. */ edges: number[]; /** Graph node ids the lap visits in order (no repeat of the closing node). */ nodes: number[]; /** Every street leaving the lap that is not part of it, closed off. */ seals: CircuitSeal[]; corners: CircuitCorner[]; /** Ordered gates, finish line last — ready for `raceTrack({ checkpoints, laps })`. */ checkpoints: CircuitGate[]; laps: number; start: CircuitStart; grid: CircuitGridSlot[]; /** Arc-length fractions (0..1) where each timing sector begins; `sectors[0]` is always 0. */ sectors: number[]; /** Share of lap length running on avenue-or-wider streets, 0..1. */ arterialShare: number; /** * Tightest radius (m) the finished racing line actually holds. `minCornerRadius` is a TARGET the * rounding pass works toward, not a guarantee: rounding may not pull the line outside the street it * inherited, so a 90° junction on a narrow road stays tighter than any target can ask for. Read * this to report what the lap really is — widen `streetWidth` to buy a smoother one. */ tightestRadius: number; } /** Kerb strips on the outside and inside of every real corner. */ export interface CircuitKerbOptions { /** Strip width across, meters. Defaults to 1.1. */ width?: number; /** Alternating stripe length along the run, meters. Defaults to 2.2. */ stripe?: number; /** Only kerb corners at or below this radius (m). Defaults to 6× the route's tightest corner. */ maxRadius?: number; } /** * Red/white kerb strips hugging both road edges through each corner. Returns the polylines and * stripe pitch as data; the renderer owns the mesh and the colors. */ export declare function circuitKerbs(route: CircuitRoute, options?: CircuitKerbOptions): CircuitKerb[]; /** * Lift a closed, sealed-off race lap out of an existing street network. Returns `null` when the * network has no drivable cycle (a pure tree of dead-end streets), so callers can fall back or warn * rather than render a broken race. * * On a `circuit`-mode network the generated loop is used directly. On a `net` (a city) the graph is * searched for the cycle closest to `lapLength` that respects `arterialBias` and `minCornerRadius`. */ export declare function extractCircuitRoute(network: StreetNetwork, rules?: Partial): CircuitRoute | null;