API Reference
API Reference
Every member below lives on window.SubwayBuilderAPI. The pages name it api:
const api = window.SubwayBuilderAPI;Every example on these pages assumes that line. Each page is generated from the game's TypeScript declarations and their JSDoc; the examples run in the game's test suite against the real API.
| Page | Members | Count | Summary |
|---|---|---|---|
| hooks | api.hooks | 32 | Lifecycle hooks: on* registrations that return an unsubscribe function. |
| actions | api.actions | 23 | Game actions: money, pause and speed, fares, bonds, station names and the demand-bubble scale. |
| gameState | api.gameState | 39 | Getters for the running game: stations, routes, tracks, trains, fares, demand, clock, money, bonds, statistics, map colors, buildings and streets, blueprint costs, station groups and save identity. |
| ui | api.ui | 26 | Mod UI: placement components, toasts, theme, CSS colors, toolbar and floating panels, and map layer visibility. |
| map | api.map | 10 | Map customization: MapLibre sources and layers, per-city tile and routing overrides, per-layer overrides, and default layer visibility. |
| trains | api.trains | 4 | Train type registry. Register, patch and read the TrainTypeStatsItem records that define both trains and the track types that share their ids. |
| stations | api.stations | 4 | Station type registry. Register, patch and read the StationTypeStatsItem records that set a station's walk catchment, transfer radius, walk speed and extra dwell. |
| build | api.build | 12 | Build automation: blueprint track placement, construction, routes and trains, through the store actions the game itself uses. |
| demand | api.demand | 8 | Demand editing: demand points and pops (commuter groups) in the loaded city. |
| popTiming | api.popTiming | 14 | Commute timing: the time-of-day ranges that weight when pops leave home and work, the student and airport dampenings, and the hour-to-demand-tier table. |
| storage | api.storage | 5 | Per-mod key-value persistence backed by a JSON file per mod id in the Electron main process. |
| registerCity | api.registerCity, api.cities | 5 | Register a city in the city picker list. |
| mods | api.mods | 2 | Registry of mods whose scripts executed without throwing. |
| tutorial | api.tutorial | 2 | Read-only tutorial state kept in sync by the tutorial start and end triggers. |
| utils | api.utils | 14 | Shared libraries and helpers: game constants, the map, city data loading, React, Lucide icons, UI components, Recharts, i18n, and the binary city-data encoders. |
| schemas | api.schemas | 6 | Zod schemas for the city data file formats. Validate generated files with safeParse. |
| Constants | api.modifyConstants, api.modifyColors, api.modifyPathfindingRules | 3 | Deep-merge overrides into the game rules object RULES and push a snapshot to the sim host worker when one is running. Full text below the table. |
| Newspaper templates | api.registerNewspaperTemplates | 1 | Append newspaper templates to the global list the newspaper service merges into its template pool. |
| Types | shared data types | 61 | Data types returned by gameState getters and carried by hook payloads. |
Constants: Deep-merge overrides into the game rules object RULES and push a snapshot to the sim host worker when one is running. The top-level RULES object keeps its identity; every nested object on an override path is replaced by a merged copy, so a nested reference taken earlier (const cc = api.utils.getConstants().CONSTRUCTION_COSTS) goes stale.
| Member | Returns | Summary |
|---|---|---|
api.version | string | API version string; the literal 1.0.0. |
api.reloadMods() | Promise<void> | Clear mod-registered state, re-execute every enabled mod through the mod loader, and resolve when the loader reports completion. |
API Structure#
window.SubwayBuilderAPI = {
version, reloadMods,
hooks: { onGameInit, onDayChange, onStationBuilt, /* 32 on* hooks */ },
actions: { setMoney, addMoney, setPause, setSpeed, addFareGroup, issueBond, /* ... */ },
gameState: { getStations, getRoutes, getTrains, getBudget, getDemandData, /* ... */ },
ui: { showNotification, addButton, addToolbarPanel, addFloatingPanel, registerComponent, /* ... */ },
map: { registerSource, registerLayer, setTileURLOverride, setLayerOverride, queryRoute, /* ... */ },
trains: { registerTrainType, modifyTrainType, getTrainTypes, getTrainType },
stations: { registerStationType, modifyStationType, getStationTypes, getStationType },
build: { placeBlueprintTracks, buildBlueprints, createRoute, buyTrains, /* ... */ },
demand: { addDemandPoint, addPops, updatePop, removePops, setPersistence, /* ... */ },
popTiming: { getCommuteTimeRanges, setCommuteTimeRange, getDemandLevel, /* ... */ },
storage: { get, set, delete, keys, scoped },
registerCity, cities: { setCityDataFiles, getCityDataFiles, registerTab, getTabs },
mods: { isLoaded, getLoadedMods },
tutorial: { isActive, getApproach },
utils: { React, icons, components, charts, i18n, buildings, walkGraph, getMap, loadCityData, /* ... */ },
schemas: { DemandDataSchema, DemandPointSchema, PopSchema, RoadsGeojsonSchema, RoadPropertiesSchema, RunwaysTaxiwaysGeojsonSchema },
modifyConstants, modifyColors, modifyPathfindingRules,
registerNewspaperTemplates,
};Quick Links#
| Task | Page |
|---|---|
| React to game events | hooks |
| Read stations, routes, money, ridership | gameState |
| Change money, speed, fares, bonds | actions |
| Add buttons, panels, notifications | ui |
| Tune game rules and pathfinding | Constants |
| Add a city | registerCity and the custom cities guide |
| Add train or station types | trains, stations |
| Build track and routes from code | build |
| Edit demand or commute timing | demand, popTiming |
| Persist mod settings | storage |
| Translate mod text | utils i18n |
| Look up a returned object's fields | Types |
| Hot reload and troubleshooting | Debugging |
TypeScript Support#
No type package ships. A mod script runs through new Function, so import statements are syntax errors in it; write a mod in TypeScript only with a build step that emits plain JavaScript. The Types page lists the returned object shapes, and each reference page gives every member's signature.
version#
api.version: stringAPI version string; the literal 1.0.0.
console.log(`Modding API ${api.version}`);reloadMods#
api.reloadMods(): Promise<void>Clear mod-registered state, re-execute every enabled mod through the mod loader, and resolve when the loader reports completion.
Cleared before the scripts re-run: every hooks.on* registration list and the onError reporter subscriptions, every mod UI component, custom map layers, sources and styles, speed overrides (restored to the original values), commute window and dampening overrides, custom newspaper templates, mod-registered cities, custom city tabs and every mod's demand.setPersistence opt-in. The loader also empties the loaded-mod registry before re-executing. Kept: registered train types and station types, tile URL, layer and routing service overrides, city data files and default layer visibility, the lifecycle markers, the tutorial state, and every storage file. After the mods re-execute the loader replays onMapReady, onGameInit, onCityLoad, onDemandChange and onGameLoaded once each for the events that already happened in the current game; onGameInit replays only in a new-game session. The Reload Mods shortcut (Cmd/Ctrl+Shift+R by default) calls this function.
Returns: Promise<void>. Promise that resolves after the modding-api-reload-complete event with no error detail.
Throws:
- loader does not report within 10000 ms: the promise rejects with
Mod reload timed out. - loader reports an error: the promise rejects with an Error carrying the loader message.
- clearing state throws: the promise rejects with that error, after logging
[Modding API] Error during state clear:and notifyingFailed to clear mod state.
Errors:
- a mod script throws during reload: the loader records an
executionerror and continues; the promise still resolves. - a mod script cannot be fetched during reload: the loader records an
initializationerror and continues; the promise still resolves.
Hooks fired:
- onMapReady (replayed when the map is loaded)
- onGameInit (replayed when the current game started as a new game)
- onCityLoad (replayed when a city is loaded)
- onDemandChange (replayed when demand is loaded)
- onGameLoaded (replayed when a save is loaded)
Side effects: in development builds logs [Modding API] Initiating hot reload... and [Modding API] State cleared for hot reload; shows the notification Mods reloading...; dispatches modding-api-reload-request on window.
Changed: reloadMods now also clears onTutorialStart and onTutorialEnd registrations, the onError reporter subscriptions, commute window and dampening overrides, custom newspaper templates and custom city tabs, and clears the new demand persistence opt-ins (PR #1090).
await api.reloadMods(); // DevTools console: re-runs every enabled mod, like Cmd/Ctrl+Shift+R