UI Customization
Add custom UI elements to the game
The UI API lets you add buttons, panels, notifications, and custom React components to the game interface.
Notifications#
showNotification#
Display a toast notification.
window.SubwayBuilderAPI.ui.showNotification('Mod loaded successfully!', 'success');
window.SubwayBuilderAPI.ui.showNotification('Something went wrong', 'error');
window.SubwayBuilderAPI.ui.showNotification('Check this out', 'info');
window.SubwayBuilderAPI.ui.showNotification('Be careful!', 'warning');UI Primitives#
Add simple UI elements without needing React knowledge.
addButton#
Add a button to a UI placement.
api.ui.addButton('settings-menu', {
id: 'my-button',
label: 'Click Me',
icon: 'Zap', // Lucide icon name (optional)
onClick: () => console.log('Button clicked!')
});addToggle#
Add a toggle switch.
api.ui.addToggle('settings-menu', {
id: 'my-toggle',
label: 'Enable Feature',
defaultValue: false,
onChange: (enabled) => console.log('Toggle:', enabled)
});addSlider#
Add a range slider.
api.ui.addSlider('settings-menu', {
id: 'speed-slider',
label: 'Speed',
min: 1,
max: 10,
step: 1,
defaultValue: 5,
onChange: (value) => console.log('Speed:', value)
});addSelect#
Add a dropdown select.
api.ui.addSelect('settings-menu', {
id: 'mode-select',
label: 'Mode',
options: [
{ value: 'easy', label: 'Easy' },
{ value: 'normal', label: 'Normal' },
{ value: 'hard', label: 'Hard' }
],
defaultValue: 'normal',
onChange: (value) => console.log('Mode:', value)
});addText#
Add static text/label.
api.ui.addText('settings-menu', {
id: 'info-text',
text: 'My Mod v1.0.0',
className: 'text-sm text-muted-foreground' // optional
});addSeparator#
Add a visual separator line.
api.ui.addSeparator('settings-menu', { id: 'my-separator' });Toolbar Buttons#
Add buttons to the top toolbar.
addToolbarButton#
api.ui.addToolbarButton({
id: 'my-button',
icon: 'Zap', // Lucide icon name
tooltip: 'Do Thing',
onClick: () => console.log('clicked!'),
isActive: () => false // Optional: return true to show "active" state
});addToolbarPanel#
Add a toolbar button that opens a floating panel.
api.ui.addToolbarPanel({
id: 'my-dashboard',
icon: 'BarChart3',
tooltip: 'My Dashboard',
title: 'Dashboard',
width: 400,
render: () => {
var h = api.utils.React.createElement;
return h('div', null, 'Hello from my panel!');
}
});The panel automatically includes:
- Styled button matching native UI
- Click-outside-to-close
- Close button (X)
- Header with title
- Proper z-index and backdrop
Main Menu Buttons#
Add buttons to the main menu with the game's signature style.
api.ui.addMainMenuButton({
id: 'my-mod-button',
text: 'My Mod',
onClick: () => console.log('Clicked!'),
description: 'Optional description text below button',
arrowBearing: 45 // optional: 0, 45, 90, 135, 180, 225, 270, 315
});Styled Components#
Use the game's actual UI components for a polished look.
addStyledButton#
api.ui.addStyledButton('settings-menu', {
id: 'my-styled-button',
label: 'Save Changes',
icon: 'Save',
variant: 'default', // 'default', 'destructive', 'outline', 'secondary', 'ghost', 'link'
size: 'default', // 'default', 'sm', 'lg', 'icon'
onClick: () => console.log('Saved!')
});addStyledToggle#
api.ui.addStyledToggle('settings-menu', {
id: 'my-styled-toggle',
label: 'Enable Feature',
defaultValue: false,
onChange: (enabled) => console.log('Toggled:', enabled)
});addStyledSlider#
api.ui.addStyledSlider('settings-menu', {
id: 'my-styled-slider',
label: 'Speed Multiplier',
min: 0.5,
max: 3.0,
step: 0.1,
defaultValue: 1.0,
showValue: true,
unit: 'x',
onChange: (value) => console.log('Speed:', value)
});Custom React Components#
For complex UIs, register custom React components.
const { React, components } = window.SubwayBuilderAPI.utils;
const h = React.createElement;
const { Card, CardHeader, CardTitle, CardContent, Button, Switch, Label } = components;
window.SubwayBuilderAPI.ui.registerComponent('settings-menu', {
id: 'my-custom-panel',
component: () =>
h(Card, { className: 'p-4' }, [
h(CardHeader, { key: 'header' },
h(CardTitle, null, 'My Panel')
),
h(CardContent, { key: 'content' }, [
h(Button, {
key: 'btn',
onClick: () => alert('Hi!')
}, 'Click Me'),
h('div', {
key: 'toggle',
className: 'flex items-center gap-2 mt-2'
}, [
h(Label, { key: 'label' }, 'Enable'),
h(Switch, { key: 'switch' })
])
])
])
});Available Components#
Components available in api.utils.components:
Button- Styled button with variantsCard,CardHeader,CardTitle,CardContent,CardDescription- Card layoutSwitch- Toggle switchSlider- Range sliderLabel- Form labelInput- Text inputBadge- Status badgeProgress- Progress barTooltip,TooltipTrigger,TooltipContent,TooltipProvider- TooltipsSubwayButton- The main menu-style arrow buttonMainMenuButton- Pre-configured SubwayButton for main menu
UI Placements#
Available placements for UI elements:
| Placement | Description |
|---|---|
settings-menu | Mod settings in Settings panel |
escape-menu | Custom menu items in escape menu |
escape-menu-buttons | Buttons in the escape/pause menu |
main-menu | Items in the main menu |
bottom-bar | Bottom UI bar (next to clock, money) |
top-bar | Top UI bar (right side toolbar) |
debug-panel | Debug info panel (when debug mode enabled) |
Theme Control#
Control the app's light/dark theme.
// Set theme
window.SubwayBuilderAPI.ui.setTheme('dark');
window.SubwayBuilderAPI.ui.setTheme('light');
window.SubwayBuilderAPI.ui.setTheme('system'); // Follow OS preference
// Get current theme setting
const themeSetting = window.SubwayBuilderAPI.ui.getTheme();
// Get actual resolved theme (useful when set to 'system')
const actualTheme = window.SubwayBuilderAPI.ui.getResolvedTheme();Color Customization#
Customize accent and primary colors.
// Set accent color
window.SubwayBuilderAPI.ui.setAccentColor('#8b5cf6'); // Purple
// Set primary color
window.SubwayBuilderAPI.ui.setPrimaryColor('#0ea5e9'); // Sky blue
// Set any CSS variable
window.SubwayBuilderAPI.ui.setCSSVariable('--radius', '0.75rem');
// Reset all colors to defaults
window.SubwayBuilderAPI.ui.resetColors();Data Visualization with Charts#
Build custom dashboards using the built-in Recharts library:
const { React, charts, components } = window.SubwayBuilderAPI.utils;
const { ResponsiveContainer, PieChart, Pie, Cell, BarChart, Bar, XAxis, YAxis, Tooltip } = charts;
const { Card, CardContent, CardHeader, CardTitle } = components;
const h = React.createElement;
// Get mode choice data
const modes = window.SubwayBuilderAPI.gameState.getModeChoiceStats();
const pieData = [
{ name: 'Transit', value: modes.transit, color: '#22c55e' },
{ name: 'Driving', value: modes.driving, color: '#ef4444' },
{ name: 'Walking', value: modes.walking, color: '#3b82f6' }
];
// Create a pie chart component
const ModeShareChart = () =>
h(Card, null, [
h(CardHeader, null, h(CardTitle, null, 'Mode Share')),
h(CardContent, null,
h(ResponsiveContainer, { width: '100%', height: 200 },
h(PieChart, null,
h(Pie, {
data: pieData,
dataKey: 'value',
nameKey: 'name',
cx: '50%',
cy: '50%',
outerRadius: 60
},
pieData.map((entry, i) =>
h(Cell, { key: i, fill: entry.color })
))
)
)
)
]);
// Register it in the UI
window.SubwayBuilderAPI.ui.registerComponent('settings-menu', {
id: 'my-mode-chart',
component: ModeShareChart
});Available Chart Types#
Access all Recharts components via api.utils.charts:
LineChart- Time series and trendsBarChart- ComparisonsAreaChart- Cumulative dataPieChart- ProportionsRadarChart- Multi-dimensional dataComposedChart- Mixed chart types
Plus all standard Recharts components: XAxis, YAxis, Tooltip, Legend, ResponsiveContainer, Cell, etc.
See the Recharts documentation for full API details.
Available Icons#
api.utils.icons exposes a curated Lucide set (PascalCase names). For the full guaranteed list, see the UI Components guide.
Access them via:
const { Train, Settings, MapPin } = api.utils.icons;