import type { Waypoint } from "./pathFollow.js"; export interface TimetableStop { at: Waypoint; /** Seconds the mover holds at this waypoint before departing. */ dwellSeconds?: number; } export interface RouteTimetableConfig { waypoints: readonly (Waypoint | TimetableStop)[]; /** World units per second between stops. */ speed: number; /** Wrap from the last waypoint back to the first (a circular line). Default `false` — the mover holds at the terminus. */ loop?: boolean; /** Default dwell applied at every waypoint without its own `dwellSeconds`; default `0`. */ dwellSeconds?: number; /** Shifts the whole timetable so `t = 0` lands mid-route — staggers several movers on one route. */ offsetSeconds?: number; } export interface TimetablePose { position: Waypoint; /** Yaw (radians) of the travel direction, matching engine `rotationY`; holds through dwells. */ heading: number; /** Index of the segment being travelled (or the stop being dwelt at). */ segment: number; /** True while holding at a stop. */ dwelling: boolean; } /** * A deterministic mover over an authored route: position is a pure function of absolute time, so a * forecast preview (`poseAt(t + 30)`) and the live mover can never disagree — the seam `nav/pathFollow`'s * dt-incremental state can't offer. Trains, ferries, patrol shuttles, crushers: anything on a timetable. */ export interface RouteTimetable { /** Seconds for one full cycle (travel + dwells); non-loop routes hold at the terminus after this. */ readonly cycleSeconds: number; readonly distance: number; poseAt(t: number): TimetablePose; positionAt(t: number): Waypoint; /** Cycle progress in `[0, 1]` — clamps at `1` on a non-looping route's terminus. */ progressAt(t: number): number; } export declare function createRouteTimetable(config: RouteTimetableConfig): RouteTimetable;