Skip to content

feat(ui): unify game and launcher themes - #3309

Merged
isaacsa2 merged 12 commits into
openOMSI-org:mainfrom
shamough1792:unify-game-theme-pr
Oct 27, 2026
Merged

isaacsa2 merged 12 commits into
openOMSI-org:mainfrom
shamough1792:unify-game-theme-pr

Conversation

@shamough1792

@shamough1792 shamough1792 commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What changes for the player?

The launcher and in-game UI now use one shared interface theme setting. Selecting Light or Dark updates the launcher, Navigator/map, Shift+Y information bar, timetable, performance panel, MileZero, trip summary, in-game popup panels, pause menu, photo mode, developer tools and plugin-hosted UI consistently.

The pause menu can also switch the theme, and the launcher reflects that choice. Existing nav_light=1 settings are migrated to the new light theme setting.

On startup and reload, the persisted game theme takes priority over an empty or stale launcher preference. System is retained only when its current OS-resolved theme matches the saved game theme; otherwise the launcher adopts the saved Light or Dark selection. Restarting the launcher therefore does not undo a game-side theme change or legacy migration.

How to test

  1. Start the launcher and select Light under Interface theme.
  2. Launch a map and verify the Navigator/map, Shift+Y information bar, timetable, performance panel and MileZero use the light palette.
  3. Open the pause menu, photo mode and developer tools and verify they use the same palette.
  4. Switch the theme from the pause menu and verify the in-game UI and launcher stay synchronized after returning to the launcher.
  5. Restart once and verify the selected theme is persisted.

Screenshots

Game settings

Dark theme

Game settings - dark theme

Light theme

Game settings - light theme

Developer tools

Dark theme

Developer tools - dark theme

Light theme

Developer tools - light theme

Pause menu

Light theme

Pause menu - light theme

Dark theme

Pause menu - dark theme

What does this change, and why?

This replaces the separate launcher/game theme behavior and the old Navigator-only light toggle with a shared ui_theme setting. A runtime palette is passed to the affected UI components, while the legacy nav_light=1 setting remains readable for backwards compatibility. The interface-theme labels and descriptions were also added/fixed in the locale data.

What could break?

The change touches shared UI palette selection and settings synchronization, so a missed UI surface could retain the old dark palette. Settings files, saves, online play and mods are not otherwise changed. The old nav_light setting is still read and migrated.

Performance

This is a palette/settings synchronization change only; no gameplay or rendering workload was added. Performance was not benchmarked.

This branch Current release 0.2.30
Average FPS Not measured N/A N/A
Slowest 1 % of frames (p99, ms) Not measured N/A N/A
Memory after 2 min (MB) Not measured N/A N/A

Machine, map and settings: Not applicable; no performance-sensitive code path was added.

Validation

  • node --experimental-vm-modules --test launcher/tests/theme-startup.test.mjs — 10 passed, covering startup/restart with empty storage, stale opposite preferences, migrated nav_light=1, all System/saved-theme combinations, game-side changes while closed, and explicit launcher changes. Tests load the actual launcher modules with a mocked transport and run in CI.
  • cargo test -p omsi-app -p omsi-plugin-ui --locked — omsi-app: 402 passed, 7 ignored; omsi-plugin-ui: 15 passed, 2 ignored.
  • cargo test -p omsi-launcher-core --locked — 105 passed, 2 ignored.
  • cargo build --release --manifest-path launcher/src-tauri/Cargo.toml — passed.
  • Launcher JavaScript tests and syntax checks — 5 passed; syntax checks passed.
  • Size budget and git diff --check — passed.
  • cargo test --workspace --locked has one pre-existing failure in omsi-cfg::codepage::tests::detects_the_code_page on this machine (咍曖 vs ЛиАЗ); this PR does not modify crates/omsi-cfg.

Checklist

  • cargo test --workspace and cargo build --release pass
  • The pull request contains a single change
  • Before/after screenshots are in the description if anything changes on screen
  • A new feature has its performance table filled in (this branch, the current release, 0.2.30)
  • New or changed interface texts are in crates/omsi-app/locales/app.yml, in every language I can
  • Online play, saves, settings and mods made for the previous release still work, or the description says what changes
  • No original OMSI 2 content and no file of a megabyte or more in the commits

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Test builds for cc00098

Platform Download
Android (arm64) android.zip
Linux x64 (game and dedicated server) linux-x64.zip
macOS (Apple silicon) macos-arm64.zip
Windows x64 (game and dedicated server) windows-x64.zip
  • Unpack the download into a new folder, not over your openOMSI. The launcher shows the version as ...-pr3309, and a test build is never updated. It shares your settings and OMSI 2 folder; mods you installed into your openOMSI folder are only seen when you unpack it into a copy of that folder.
  • Android: the download holds an APK that installs as a separate app, openOMSI PR feat(ui): unify game and launcher themes #3309, beside the release, and shares its openOMSI folder.
  • What to try is under How to test in the description. Please comment with what you found and the version the launcher shows.
  • The links work for 14 days after the build.

# Conflicts:
#	crates/omsi-app/src/game_lists/menu_pages.rs
#	crates/omsi-app/src/game_lists/options.rs
#	crates/omsi-app/src/settings.rs
#	crates/omsi-app/src/settings/tests.rs
#	crates/omsi-launcher-core/src/lib.rs
#	launcher/ui/js/pages/settings-schema.js

@isaacsa2 isaacsa2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 2954ffe. There is a persistence bug in launcher/ui/js/data.js: boot() installs the settings returned by bootstrap, then applyTheme() resolves the launcher's old localStorage preference (defaulting to dark) and saves it over ui_theme.

I reproduced this with the branch's actual data.js and a mocked bootstrap/settings transport: saved ui_theme=light plus empty launcher storage produced settings_patch({ui_theme: "dark"}) during boot. This also undoes the nav_light=1 migration, and can undo a theme changed in-game while the launcher is closed. reloadSettings() handles the opposite direction, but boot() does not.

Please reconcile the persisted game setting before the first applyTheme(), with an explicit policy for System, and add startup/restart regressions for empty storage, a stale opposite launcher preference and legacy nav_light=1. The current self-test only changes themes after boot. CI is green; this is a reproduced startup bug, not a build failure. I have not run the game locally.

Luc-nbr added a commit to Luc-nbr/openOMSI-upstream that referenced this pull request Oct 26, 2026
…three files under their size

- main merged again (settings.rs: nav_classic_2d beside the theme pack).
- openOMSI-org#3309 (open) makes `ui_theme` the light or dark interface theme, with the row "Interface
  theme". This PR's setting is now `ui_theme_pack`, its row "Theme pack" (in the 29 languages
  of the Interface page): a theme pack is a look a mod or plugin brings, the light or dark theme
  is openOMSI's own; the two keys no longer clash, whichever is merged first.
- Under the size budget by moving cohesive parts into modules, not by raising limits:
  - omsi-app: the loading screen's drawing (the wordmark, the striped bar, an interface theme's
    logo and marks) is `ui/loading.rs` (ui.rs 1852 -> 1671 lines, its budget 1810);
  - omsi-plugin-ui: the panels' colours (the card, the accent, the menus' greys) are `look.rs`
    (lib.rs 1510 -> 1486);
  - omsi-plugin: the navigator's board (`Dock`, `set_dock`, `dock`) is `ui/dock.rs`, as the pause
    menu's lines (`ui/menu.rs`) and the themes (`ui/theme.rs`) are (ui.rs 1507 -> 1482).
  scripts/size-budget.sh and scripts/arch-guard.sh pass.
@shamough1792

Copy link
Copy Markdown
Contributor Author

Fixed in 1f2c40c.

boot() now reconciles the persisted game theme before the first applyTheme() and awaits that call. Startup and reloadSettings() share the same reconciliation logic, so an empty or stale launcher preference cannot overwrite the saved ui_theme.

System policy: the persisted game theme takes priority on startup/reload. The launcher retains System only when its current OS-resolved theme matches the saved game theme; otherwise it adopts the saved explicit Light/Dark selection. Explicit user changes in the launcher still persist normally.

Added startup/restart regressions using the actual launcher modules with a mocked bootstrap/settings transport. Coverage includes empty storage, stale opposite preferences in both directions, the bootstrap result of legacy nav_light=1 migration, all System/saved-theme combinations, a game-side change while the launcher is closed, and an explicit launcher change surviving restart. These tests now run in PR CI.

Validation:

  • Before the fix: 7 of the initial 9 regression cases failed, reproducing the startup issue.
  • After the fix: all 10 startup/restart tests passed.
  • The existing Rust launcher_settings_bridge_unifies_ui_theme_with_legacy_nav_light regression passed, verifying the legacy settings-to-bootstrap migration contract.
  • JavaScript syntax and git diff --check passed.

I have not run the game or rebuilt the test executables for this follow-up; the results above are automated module/transport and backend migration checks, not runtime game validation.

@isaacsa2 isaacsa2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked 1f2c40c. Startup now reconciles the persisted game theme before applyTheme(), and the new tests cover empty/stale launcher storage, legacy migration, restart and System. That addresses the startup overwrite I reproduced. Current CI is green, but the branch conflicts with current main in game_panels/mod.rs, preview.rs, quick_menu.rs, settings.rs and omsi-launcher-core/src/lib.rs. The quick menu was reworked on main, so this needs a semantic integration that preserves the new menu behaviour and applies the palette to it; choosing one side wholesale would lose work. Please update the branch, recheck both themes on the new menu and rerun CI before approval. #3278 now uses ui_theme_pack, so the setting names are separate, though the shared palette implementation still needs coordination. I reviewed the follow-up code and tests, not a local gameplay run.

Signed-off-by: Isaac S. <107325320+isaacsa2@users.noreply.github.com>
Signed-off-by: Isaac S. <107325320+isaacsa2@users.noreply.github.com>
Add test for square tiles to follow the selected palette while maintaining lit and disabled states.

Signed-off-by: Isaac S. <107325320+isaacsa2@users.noreply.github.com>
@isaacsa2

Copy link
Copy Markdown
Contributor

Resolved the conflicts with main in f00b2f0. The two-page quick menu keeps its keyboard navigation, mouse hover, lit tiles and unavailable actions, and now uses the shared Light/Dark palette. The settings merge also keeps cab_wheel_rotation and the saved theme behavior.

Added a regression test for the new icon-only tiles in both themes, including focus, the white icon on a lit tile, and no click target for a disabled tile.

On cc00098, all 10 launcher theme startup/restart tests pass locally; size budget, crate layers and whitespace checks pass too. The Rust tests and platform builds are still running in CI. I have not tested this integration in the game.

@isaacsa2 isaacsa2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked cc00098. The startup overwrite is fixed, and the merge keeps the two-page quick menu, its navigation, lit tiles and disabled actions while applying the selected palette. I reran the 10 startup/restart tests against this head; all pass. Size budget, crate layers and whitespace checks pass locally, and the current Release, PR checks, CodeQL and secret scan are green.

My previous blockers are resolved. Approving this head. The overlap with #3278 still needs a fresh integration check on whichever branch lands second; the separate ui_theme and ui_theme_pack keys should both survive. I reviewed the code and automated results, not a new local gameplay run or FPS benchmark.

@isaacsa2
isaacsa2 merged commit 908d130 into openOMSI-org:main Oct 27, 2026
12 checks passed
isaacsa2 added a commit to isaacsa2/openOMSI that referenced this pull request Oct 27, 2026
Luc-nbr added a commit to Luc-nbr/openOMSI-upstream that referenced this pull request Oct 27, 2026
…s over Light or Dark

Main put the light look in a `Theme` of its own, read from `Ui::theme` (`set_theme(light)`)
and passed to the plugin panels as `ThemeColors::new(light)`; this branch reads the palette
in force, `omsi_ui::theme::th()`. Kept both, a pack's colours showed only where `th()` is
read and Light only where `self.theme` is. Now there is one source of colours:

- `omsi_ui::theme::Palette::LIGHT` is main's light look and `theme::palette(light)` gives
  openOMSI's dark or light palette; `Palette::with_colors` lays a theme's colours over the one
  given, and the theme's radius and glass go on top (`themes::Theme::palette(light)`).
- `themes::sync(pack, light)` puts that in force (the theme read anew only when it is
  another); the pause menu, developer tools and photo mode call it where main called
  `set_theme`. `Ui::theme`, `Ui::set_theme`, `Shell::set_theme` and `theme::Theme` are gone;
  main's lines read `th()`, with its light-look fixes kept (accent ink on buttons, the
  toggle, slider, segment and progress tracks, tooltips and popups from the palette).
- The plugin panels' `ThemeColors::of(palette)` keeps openOMSI's dark greys exactly and takes
  any other palette's surfaces and inks; a card is laid out again when the palette changes
  (`PanelsFrame::palette` for main's `light`). The game's own panels take the palette
  (`themes::palette(light)`) rather than `light`.
- The settings keep both: `ui_theme` (Light or Dark) and `ui_theme_pack`.
- docs/THEMES.md: a theme goes over the look the player chose.

Main's tests for the light look run on the palette (`with_palette`); a test for a theme over
the light look.
Luc-nbr added a commit to Luc-nbr/openOMSI-upstream that referenced this pull request Oct 31, 2026
Conflicts: settings.rs Default keeps main's line (passenger_*, road_snow, light_shadows
"off") with ui_theme_pack added back; integrations.rs keeps themes_for_load and passes
no_plugins to load; game_panels/mod.rs keeps the pal panels and adds main's multiplayer one.

openOMSI-org#3488's multiplayer form was written against openOMSI-org#3309's light: bool: panel/panel_of now take
pal: Palette like the other forms (heading in pal.text, note and card with pal), and its
preview loops over the dark and Light palettes. settings_from_text_on went to 302 lines with
the theme pack's default: the voice-chat defaults move to voice_defaults, as
passenger_defaults.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants