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.

javascript
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.

javascript
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.

javascript
api.ui.addToggle('settings-menu', {
    id: 'my-toggle',
    label: 'Enable Feature',
    defaultValue: false,
    onChange: (enabled) => console.log('Toggle:', enabled)
});

addSlider#

Add a range slider.

javascript
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.

javascript
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.

javascript
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.

javascript
api.ui.addSeparator('settings-menu', { id: 'my-separator' });

Toolbar Buttons#

Add buttons to the top toolbar.

addToolbarButton#

javascript
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.

javascript
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

Add buttons to the main menu with the game's signature style.

javascript
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#

javascript
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#

javascript
api.ui.addStyledToggle('settings-menu', {
    id: 'my-styled-toggle',
    label: 'Enable Feature',
    defaultValue: false,
    onChange: (enabled) => console.log('Toggled:', enabled)
});

addStyledSlider#

javascript
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.

javascript
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 variants
  • Card, CardHeader, CardTitle, CardContent, CardDescription - Card layout
  • Switch - Toggle switch
  • Slider - Range slider
  • Label - Form label
  • Input - Text input
  • Badge - Status badge
  • Progress - Progress bar
  • Tooltip, TooltipTrigger, TooltipContent, TooltipProvider - Tooltips
  • SubwayButton - The main menu-style arrow button
  • MainMenuButton - Pre-configured SubwayButton for main menu

UI Placements#

Available placements for UI elements:

PlacementDescription
settings-menuMod settings in Settings panel
escape-menuCustom menu items in escape menu
escape-menu-buttonsButtons in the escape/pause menu
main-menuItems in the main menu
bottom-barBottom UI bar (next to clock, money)
top-barTop UI bar (right side toolbar)
debug-panelDebug info panel (when debug mode enabled)

Theme Control#

Control the app's light/dark theme.

javascript
// 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.

javascript
// 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:

javascript
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 trends
  • BarChart - Comparisons
  • AreaChart - Cumulative data
  • PieChart - Proportions
  • RadarChart - Multi-dimensional data
  • ComposedChart - 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:

javascript
const { Train, Settings, MapPin } = api.utils.icons;