/** A path vertex in the volume-local XZ frame. */ export type StreetVec2 = readonly [number, number]; /** Road hierarchy, widest to narrowest — shared by the city fabric and the renderer. */ export type StreetLevel = "boulevard" | "avenue" | "street" | "lane"; /** A path feature spanning part of an edge/street: a bridge deck over a gap or a tunnel bore under a ridge. */ export type StreetFeatureKind = "bridge" | "tunnel"; /** The generator's chosen topology family: an open street `net`, or a closed `circuit` loop. */ export type StreetNetworkMode = "net" | "circuit"; /** One graph node: a junction, a dead end, or a mid-street bend, with its connection count. */ export interface StreetNode { id: number; x: number; z: number; degree: number; } /** One atomic node-to-node edge — the fabric graph consumes these (welds at shared node coords). */ export interface StreetEdge { id: number; /** Endpoint node ids. */ a: number; b: number; /** Sampled centerline; `points[0]` sits exactly on node `a`, the last on node `b`. */ points: StreetVec2[]; width: number; level: StreetLevel; /** True when this edge belongs to the main closed loop (circuit mode). */ loop: boolean; /** Per-point road-surface height (one per `points`), present only when `elevation > 0`. Raw * (uncapped) samples of {@link StreetNetwork.elevationAt}; the grade-limited profile lives on the * owning {@link Street.heights}. */ heights?: number[]; } /** A feature span carried by a street: a `[from, to]` index window into the street's `points`. */ export interface StreetFeatureSpan { kind: StreetFeatureKind; from: number; to: number; /** Ground height at each bank/portal — the deck/floor reference the renderer drapes to. */ bankHeight: number; } /** Left/right pedestrian bands flanking a street's asphalt, as offset polylines. */ export interface StreetSidewalks { /** Polyline offset to the left of travel (parallel to `points`). */ left: StreetVec2[]; /** Polyline offset to the right of travel. */ right: StreetVec2[]; } /** One chained through-street: a maximal run of edges through degree-2 nodes, for rendering + furniture. */ export interface Street { id: number; /** Ordered node ids the chain visits; first === last when `loop`. */ nodes: number[]; /** Smoothed, arc-filleted centerline. */ points: StreetVec2[]; width: number; level: StreetLevel; /** Closed chain (a circuit lap or an inner ring). */ loop: boolean; /** Cul-de-sac turning bulb when the street ends at a dangling node. */ bulb?: StreetVec2; /** Bridge/tunnel spans along this street, if any. */ features: StreetFeatureSpan[]; /** Flanking pedestrian bands, present on boulevard/avenue/street levels (not lanes). */ sidewalks?: StreetSidewalks; /** Per-point road-surface height (one per `points`), present only when `elevation > 0`. Grade-limited * so no consecutive pair exceeds `maxGrade`; a loop stays continuous (`heights[0] === heights.at(-1)`). * This is ROAD elevation, not the `context.heightAt` terrain that drives bridges/tunnels. */ heights?: number[]; } /** One crossing of three or more streets: patch center/radius plus outgoing arm directions. */ export interface StreetJunction { x: number; z: number; radius: number; level: StreetLevel; /** Outgoing arm directions (radians) with the crossing street width, for crosswalks/patches. */ arms: { angle: number; width: number; }[]; } /** One dangling street end kept as a cul-de-sac: node position plus the heading pointing off the road. */ export interface StreetDeadEnd { node: number; x: number; z: number; /** Yaw (radians) facing outward, away from the network. */ heading: number; width: number; } /** A resolved path feature in world-of-the-volume space: a bridge deck or tunnel bore centerline. */ export interface StreetFeature { kind: StreetFeatureKind; points: StreetVec2[]; width: number; bankHeight: number; } /** The fully-resolved network in volume-local coords. */ export interface StreetNetwork { mode: StreetNetworkMode; nodes: StreetNode[]; /** Atomic edges — feed to the block/parcel fabric. */ edges: StreetEdge[]; /** Chained through-streets — feed to the renderer, furniture, and analysis. */ streets: Street[]; junctions: StreetJunction[]; deadEnds: StreetDeadEnd[]; bridges: StreetFeature[]; tunnels: StreetFeature[]; /** Independent cycle count (E − V + components): 0 = pure tree, ≥1 = has loops. */ loops: number; /** The shared road-surface height FIELD (volume-local), present only when `elevation > 0`. Sample it * to drape junction welds, sidewalks, and building bases so every surface meets the road continuously * — the streets/edges sample this exact field. Distinct from the `context.heightAt` terrain sampler. */ elevationAt?: (x: number, z: number) => number; } /** Fully-defaulted slider set the generator reads. */ export interface StreetNetworkRules { seed: string; /** Organic boundary clipping amount, when supported by the caller. */ outline?: number; /** 1 = regular lattice nodes; 0 = organic scatter. */ gridness: number; /** 0 = tree (dead-ends); 1 = a single closed circuit. */ loopiness: number; /** Extra chord edges between neighbors → mesh density. */ connectivity: number; /** Spur-lane density forking off the mains (and, in a circuit, the pit-lane trigger). */ branching: number; /** Share of branch streets that use residential side-street rules. */ residentialBranches?: number; /** Fraction of dangling ends kept as cul-de-sacs (vs reconnected). */ deadEnds: number; /** Target node spacing / block size, world units. */ segmentLength: number; /** Cross-axis spacing multiplier (≥1 = long skinny Manhattan blocks). */ aspect: number; /** Sideways wander amplitude, 0..1 (and circuit corner-template density). */ winding: number; /** Minimum curve radius (m) — caps wander curvature and sets the corner-fillet radius. */ minCurveRadius: number; /** Shallowest corner (degrees) a street keeps — gentler bends are straightened. */ minTurnAngle: number; /** Sharpest corner (degrees) between consecutive centerline samples — sharper corners are filleted. */ maxTurnAngle: number; /** Base street width; the hierarchy scales off it. */ width: number; /** Share of avenues upgraded to boulevards, 0..1. */ boulevards: number; /** Pedestrian band width paved on each side of boulevard/avenue/street levels. Default ~2. */ sidewalkWidth?: number; /** Road-surface relief amplitude, 0..1. 0 (default) = dead flat and byte-identical to a pre-elevation * network; 1 ≈ 22 m of relief across a ~520 m volume (scaled to the footprint). */ elevation?: number; /** Maximum road slope (rise/run) the grade cap enforces on every street's height sequence. Default 0.07. */ maxGrade?: number; /** SPACE-FILLING circuit layout dial, 0..1. 0 (default) = the hull construction (a flowing loop around * an empty middle), BYTE-IDENTICAL to a pre-compactness network. Rising values switch the circuit * LAYOUT stage to a grid spanning-tree CYCLE that folds back through its own interior: parallel * adjacent runs one corridor pitch apart, switchback esses, consecutive hairpins, and long straights * from straight tree branches, with footprint coverage rising with the dial (~45% of grid cells at * 0.5, ~85% at 1). Everything downstream — spline fit, curvature floor, straight designation, * self-clearance, edge distribution, elevation, pit lane — is reused unchanged. Only meaningful in * circuit mode; ignored by the street net. */ compactness?: number; } /** Ground sampler + feature toggles enabling bridges/tunnels; omit for a flat, feature-free network. */ export interface StreetNetworkContext { /** Volume-local ground height sampler. */ heightAt?: (x: number, z: number) => number; /** Ground below this (local) height is a gap streets bridge over. */ minElevation?: number; /** Emit bridge decks over sub-`minElevation` gaps. */ bridges?: boolean; /** Emit tunnel bores where the ground rises this far above a span's banks. */ tunnels?: boolean; /** Ridge height above the banks that triggers a tunnel. Default 6. */ tunnelClearance?: number; } /** * Replace every real corner of a polyline with a sampled **circular-arc fillet** so bends read as * smooth curves instead of polygonal notches, while enforcing two hard limits with fixed endpoints: * interior corners gentler than `minRad` are straightened away (deliberate winding only, no * micro-wiggle), and each remaining corner is rounded with an arc of radius `curveRadius` (clamped to * half the shorter adjacent leg) sampled finely enough that no discrete turn between consecutive * samples exceeds `maxRad` — a corner sharper than the ceiling is still reduced, now to a fillet * rather than a bevel. Open-chain endpoints never move (a graph node stays welded); pass `closed` for * a ring (first === last) so its wrap corner is filleted too and the loop stays closed. * * Pass `radiusFor` to vary the fillet radius PER CORNER (returning the target radius from the corner's * deflection and adjacent leg lengths) instead of the single `curveRadius` — the circuit loop uses this * to mix hairpins, standard corners, and sweepers; every other caller keeps the scalar radius. * @internal */ export declare function clampTurns(points: readonly StreetVec2[], minRad: number, maxRad: number, curveRadius?: number, closed?: boolean, radiusFor?: (deflection: number, la: number, lb: number) => number): StreetVec2[]; /** Decide which topology family the sliders call for. Circuit wins when loops dominate and both * branching and mesh connectivity are low — exactly the "race track" corner of the slider space. * @internal */ export declare function streetNetworkMode(rules: StreetNetworkRules): StreetNetworkMode; /** * Resolve a full path network from its rules inside a volume of half-extents `hx`×`hz`. Deterministic * per `(rules.seed, hx, hz, context)`. Pass a {@link StreetNetworkContext} with a ground sampler to turn * water gaps into bridges and ridges into tunnels. Coordinates are volume-local; the caller maps to * world space. * * @capability street-generator build a deterministic street/track graph (nodes, edges, streets, junctions, sidewalks, bridges, tunnels) from sliders */ export declare function generateStreets(rules: StreetNetworkRules, hx: number, hz: number, context?: StreetNetworkContext): StreetNetwork;