import type { RoadEnvironmentDescriptor } from "./features.js"; import { type DashExclusion, type RoadPoint } from "./roads.js"; /** * Offset a centerline sideways by a signed distance along its local perpendicular — the * building block for lanes, curb lines, and sidewalk paths. Positive offsets fall on the * left of the direction of travel, negative on the right. */ export declare function offsetPath(path: readonly RoadPoint[], offset: number): readonly RoadPoint[]; /** A directed lane derived from a road: an offset centerline plus its direction of travel. */ export interface StreetLane { /** Lane centerline, ordered in the direction of travel. */ path: readonly RoadPoint[]; /** "forward" runs with the road's declared path order; "reverse" runs against it. */ direction: "forward" | "reverse"; } /** * Two right-hand-traffic lane centerlines for a road — each offset a quarter of the drivable * width from the center and ordered in its direction of travel. Feed a lane's `path` straight * into `nav/pathFollow` for traffic AI, or use its endpoints as directed car spawn points. */ export declare function laneCenters(road: RoadEnvironmentDescriptor): readonly [StreetLane, StreetLane]; /** Resolved sidewalk band widths for a road; zero when the road declares no sidewalk. */ export declare function sidewalkWidthOf(road: RoadEnvironmentDescriptor): number; /** * The two sidewalk walking paths of a road — offset polylines running down the middle of each * sidewalk band. Pedestrians spawn and route along these instead of the asphalt. */ export declare function sidewalkPaths(road: RoadEnvironmentDescriptor): readonly (readonly RoadPoint[])[]; /** A placement anchor on the curb line: position, outward-facing heading, and which side it sits on. */ export interface FurnitureSpot { position: RoadPoint; /** Yaw (radians, engine `rotationY` convention) facing away from the road. */ heading: number; side: "left" | "right"; /** Arc-length distance along the road at this spot. */ along: number; } /** Options for {@link furnitureSpots}. */ export interface FurnitureSpotOptions { /** Distance between consecutive spots along the road. Default 24. */ spacing?: number; /** Which curb lines to populate. Default "both". */ sides?: "both" | "left" | "right"; /** Alternate sides spot-by-spot instead of mirroring every spot. Default true. */ stagger?: boolean; /** Extra outward shift past the curb line (e.g. to center furniture in the sidewalk). Default 0. */ outset?: number; } /** * Evenly spaced street-furniture anchors along a road's curb lines — streetlights, palms, signs, * hydrants, benches. Each spot sits just outside the asphalt (plus `outset`), faces away from * the street, and alternates sides by default so lights stagger like a real avenue. This is the * answer to "where do I put it": furniture is an asset of the street, never a hand-typed coordinate. */ export declare function furnitureSpots(road: RoadEnvironmentDescriptor, options?: FurnitureSpotOptions): readonly FurnitureSpot[]; /** Options for {@link parkingSpots}. */ export interface ParkingSpotOptions { /** Distance between consecutive parked-car anchors. Default 18. */ spacing?: number; /** Which side(s) of the street to line with parking. Default "both". */ sides?: "both" | "left" | "right"; } /** A curbside parking anchor: position at the road edge and a heading parallel to the street. */ export interface ParkingSpot { position: RoadPoint; /** Yaw (radians) aligned with the direction of travel on that side (right-hand traffic). */ heading: number; side: "left" | "right"; } /** * Curbside parking anchors along a road: hugging the edge of the asphalt, headed parallel to the * street in that side's direction of travel. Spawn parked vehicles here instead of eyeballing * coordinates in the middle of the carriageway. */ export declare function parkingSpots(road: RoadEnvironmentDescriptor, options?: ParkingSpotOptions): readonly ParkingSpot[]; /** * Signed planar distance from `(x, z)` to the nearest road *surface edge* across every segment of * every road (#1051): negative inside the asphalt (magnitude = how far in from the closest edge, so * `-width/2` on the centerline), `~0` right at the curb, and positive off the road (the gap to the * nearest edge). Point-to-segment distance minus the road's half width, minimised over all segments — * the "am I on the road, and by how much" seam driving grip, tyre audio, and off-road penalties. * * Allocation-free per call (only scalars — no arrays or objects) so a per-tick car sim can sample it * on the hot path; degenerate roads (fewer than two path points) contribute nothing, and with no road * surface at all it returns {@link Number.POSITIVE_INFINITY} (everywhere is off-road). */ export declare function distanceToRoadEdge(roads: readonly RoadEnvironmentDescriptor[], x: number, z: number): number; /** Grip levels and blend width for {@link roadSurfaceSampler}; each field is optional and defaulted. */ export interface RoadSurfaceOptions { /** Grip multiplier on the asphalt. Default 1. */ onRoad?: number; /** Grip multiplier once fully off the road past the shoulder. Default 0.72. */ offRoad?: number; /** Width (world units) of the blend band outside the curb from full to off-road grip. Default 3. */ shoulder?: number; } /** * A `surfaceFriction`-compatible sampler (the `(x, z) => grip` hook a kinematic car reads each tick) * that turns road geometry into grip (#1051): full `onRoad` grip on the asphalt, a monotonic linear ramp * down across a `shoulder`-wide band at the curb, and flat `offRoad` grip beyond it — so a car that * clips onto the grass loses bite progressively instead of snapping. Closes over {@link * distanceToRoadEdge}, so the returned sampler is itself allocation-free per call. */ export declare function roadSurfaceSampler(roads: readonly RoadEnvironmentDescriptor[], options?: RoadSurfaceOptions): (x: number, z: number) => number; /** * A deterministic point on one of a road's sidewalks at a normalized position — `side` picks the * band, `fraction` (0..1) picks how far along. The canonical pedestrian spawn helper. */ export declare function sidewalkPoint(road: RoadEnvironmentDescriptor, side: "left" | "right", fraction: number): RoadPoint | null; /** * The two curb lines of a road — offset polylines running along the outer edge of the asphalt on * each side. Mesh these with a thin darker ribbon to give the road a curb/edge strip instead of a * hard asphalt-to-terrain seam. `inset` (default 0) nudges the line inward off the raw edge so the * strip straddles the border. */ export declare function curbPaths(road: RoadEnvironmentDescriptor, inset?: number): readonly [readonly RoadPoint[], readonly RoadPoint[]]; /** A single arm of a junction: the road width plus the outward direction the road leaves the center. */ export interface RoadApproach { /** Unit vector pointing from the junction center outward along the road arm. */ direction: readonly [number, number]; /** Drivable width of the road on this arm. */ width: number; } /** A welded road intersection: a patch center/radius plus the arms that feed it. */ export interface RoadJunction { /** World XZ center of the intersection. */ center: RoadPoint; /** Radius of the covering patch (covers the crossing ribbons). */ radius: number; /** Representative surface elevation (max of the participating roads). */ elevation: number; /** Representative asphalt color (the widest participating road's color). */ color: string; /** Outward arms leaving the junction — one per road direction that continues past the center. */ approaches: readonly RoadApproach[]; } /** Options for {@link findRoadJunctions}. */ export interface RoadJunctionOptions { /** Roads weld only when their elevations differ by at most this much. Default 0.12. */ elevationBand?: number; /** Crossing points closer than this merge into a single junction. Default 6. */ mergeDistance?: number; /** Hard cap on junctions returned so detection stays bounded. Default 256. */ maxJunctions?: number; /** Extra scale on the patch radius past the widest arm's half-width. Default 1.15. */ radiusScale?: number; } /** * Detect welded intersections across a set of roads: wherever two road centerlines cross (or a road * terminates on another) within the same elevation band, emit a {@link RoadJunction} whose patch * covers the crossing ribbons. Nearby crossings merge into one junction. Deterministic and bounded — * O(roads² · segments²) with a `maxJunctions` cap — so a scene builds its intersections once. */ export declare function findRoadJunctions(roads: readonly RoadEnvironmentDescriptor[], options?: RoadJunctionOptions): readonly RoadJunction[]; /** Circular marking-exclusion zones for the junctions, sized to hide the center line under each patch. */ export declare function junctionExclusions(junctions: readonly RoadJunction[], pad?: number): readonly DashExclusion[]; /** Options for {@link junctionMarkings}. */ export interface JunctionMarkingOptions { /** Emit a stop-line bar across each approach. Default true. */ stopLines?: boolean; /** Emit crosswalk bars at each approach. Default true. */ crosswalks?: boolean; /** Number of zebra bars per crosswalk. Default 5. */ crosswalkBars?: number; /** Clear gap outside the patch before markings start. Default 0.6. */ gap?: number; /** Depth (along travel) of the crosswalk band. Default 2.4. */ crosswalkDepth?: number; } /** Thin marking polylines for a junction: stop-line bars and crosswalk bars, ready for {@link buildRoadRibbon}. */ export interface JunctionMarkings { /** One bar per approach, perpendicular to travel just outside the patch. */ stopLines: readonly (readonly RoadPoint[])[]; /** Continental (parallel-to-travel) zebra bars, `crosswalkBars` per approach. */ crosswalkBars: readonly (readonly RoadPoint[])[]; } /** * Data-driven junction entry markings: a stop-line bar across each approach and a band of crosswalk * bars just outside the welded patch. Each returned polyline is a thin centerline meant to be meshed * with {@link buildRoadRibbon} at a small width. Fully skippable per-feature via the options. */ export declare function junctionMarkings(junction: RoadJunction, options?: JunctionMarkingOptions): JunctionMarkings;