@@ -186,7 +186,7 @@ watch(
'/clients': 'clients.nav',
'/webrtc': 'webrtc.nav',
};
- const v = map[p] || 'Vibepollo';
+ const v = map[p] || 'Nimbus';
pageTitle.value = v;
},
{ immediate: true },
diff --git a/src_assets/common/assets/web/Login.vue b/src_assets/common/assets/web/Login.vue
index 4b67128930..cbc4fca228 100644
--- a/src_assets/common/assets/web/Login.vue
+++ b/src_assets/common/assets/web/Login.vue
@@ -5,7 +5,7 @@
-
+ {{ $t('auth.login_title') }}
@@ -111,7 +111,7 @@ function redirectNowIfAuthenticated() {
}
onMounted(() => {
- document.title = `Vibepollo - ${t('auth.login_title')}`;
+ document.title = `Nimbus - ${t('auth.login_title')}`;
const urlParams = new URLSearchParams(window.location.search);
const redirectParam = urlParams.get('redirect');
if (redirectParam) {
diff --git a/src_assets/common/assets/web/ResourceCard.vue b/src_assets/common/assets/web/ResourceCard.vue
index 0f068fa16a..b8bf6031df 100644
--- a/src_assets/common/assets/web/ResourceCard.vue
+++ b/src_assets/common/assets/web/ResourceCard.vue
@@ -84,14 +84,14 @@ const resources = computed(() => [
avatarStyle: 'background-color: rgba(99, 102, 241, 0.15); color: rgb(99, 102, 241);',
},
{
- href: 'https://github.com/Nonary/Vibepollo/discussions',
+ href: 'https://github.com/kunolabs/Nimbus/discussions',
icon: 'fab fa-github',
title: t('resource_card.github_discussions'),
description: 'GitHub Discussions',
avatarStyle: 'background-color: rgba(16, 185, 129, 0.15); color: rgb(16, 185, 129);',
},
{
- href: 'https://github.com/Nonary/Vibepollo/issues',
+ href: 'https://github.com/kunolabs/Nimbus/issues',
icon: 'fab fa-github',
title: 'GitHub Issues',
description: 'Report bugs or request features',
@@ -101,14 +101,14 @@ const resources = computed(() => [
const legalLinks = computed(() => [
{
- href: 'https://github.com/Nonary/Vibepollo/blob/master/LICENSE',
+ href: 'https://github.com/kunolabs/Nimbus/blob/master/LICENSE',
icon: 'fas fa-file-alt',
title: t('resource_card.license'),
description: 'View license',
avatarStyle: 'background-color: rgba(34, 197, 94, 0.15); color: rgb(34, 197, 94);',
},
{
- href: 'https://github.com/Nonary/Vibepollo/blob/master/NOTICE',
+ href: 'https://github.com/kunolabs/Nimbus/blob/master/NOTICE',
icon: 'fas fa-exclamation',
title: t('resource_card.third_party_notice'),
description: 'Third-party notices',
diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json
index 6485ab5562..940ec1946c 100644
--- a/src_assets/common/assets/web/public/assets/locale/en.json
+++ b/src_assets/common/assets/web/public/assets/locale/en.json
@@ -369,11 +369,11 @@
"gamepad_x360": "X360 (Xbox 360)",
"gamepad_xone": "XOne (Xbox One)",
"vigem_missing_title": "Virtual Gamepad Driver (ViGEm) not installed",
- "vigem_missing_desc": "Vibepollo requires the ViGEmBus driver to emulate controllers on Windows. It is no longer bundled. Please download and install it manually:",
+ "vigem_missing_desc": "Nimbus requires the ViGEmBus driver to emulate controllers on Windows. It is no longer bundled. Please download and install it manually:",
"vigem_install": "Download ViGEmBus",
"vigem_detected_version": "Detected",
"crash_dump_title": "Recent crash detected",
- "crash_dump_desc": "Vibepollo detected a crash dump within the last week. Please export a crash bundle and include it when opening an issue.",
+ "crash_dump_desc": "Nimbus detected a crash dump within the last week. Please export a crash bundle and include it when opening an issue.",
"crash_dump_export": "Export Crash Bundle",
"crash_dump_export_preparing": "Preparing Crash Bundle...",
"crash_dump_export_error": "Failed to export crash bundle.",
@@ -613,23 +613,23 @@
"legacy_ordering_desc": "Enable ordering support workaround for legacy clients. Can cause issues with clients or scripts that can't handle UTF8 correctly. Artemis clients support this by default."
},
"index": {
- "description": "Vibepollo is a self-hosted game stream host for Moonlight.",
+ "description": "Nimbus is a self-hosted game stream host for Moonlight-compatible clients.",
"download": "Download",
"view_notes": "Release Notes",
"hide_notes": "Hide Notes",
- "installed_version_not_stable": "You are running a pre-release version of Vibepollo. You may experience bugs or other issues. Please report any issues you encounter. Thank you for helping to make Vibepollo a better software!",
+ "installed_version_not_stable": "You are running a pre-release version of Nimbus. You may experience bugs or other issues. Please report any issues you encounter. Thank you for helping to make Nimbus better!",
"loading_latest": "Loading latest release...",
"new_pre_release": "A new Pre-Release Version is Available!",
"new_stable": "A new Stable Version is Available!",
- "startup_errors": "Attention! Vibepollo detected these errors during startup. We STRONGLY RECOMMEND fixing them before streaming.",
- "version_dirty": "Thank you for helping to make Vibepollo a better software!",
- "version_latest": "You are running the latest version of Vibepollo",
+ "startup_errors": "Attention! Nimbus detected these errors during startup. We STRONGLY RECOMMEND fixing them before streaming.",
+ "version_dirty": "Thank you for helping to make Nimbus better!",
+ "version_latest": "You are running the latest version of Nimbus",
"version_ahead": "You are running a development build ahead of the latest release ({ahead} commits)",
"version_behind": "Your build is {behind} commits behind the latest release; consider updating.",
"version_compare_unknown": "Unable to determine commit distance to latest release.",
"version_branch": "Branch: {branch} (commit {commit})",
"view_logs": "Open Troubleshooting — Logs",
- "welcome": "Hello, Vibepollo!"
+ "welcome": "Hello, Nimbus!"
},
"resources": {
"title": "Resources"
@@ -1096,7 +1096,7 @@
"license": "License",
"resources": "Resources",
"discord_desc": "Join the community",
- "resources_desc": "Resources for Vibepollo!",
+ "resources_desc": "Resources for Nimbus!",
"third_party_notice": "Third Party Notice"
},
"troubleshooting": {
@@ -1166,8 +1166,8 @@
"welcome": {
"confirm_password": "Confirm password",
"create_creds": "Before Getting Started, we need you to make a new username and password for accessing the Web UI.",
- "create_creds_alert": "The credentials below are needed to access Vibepollo's Web UI. Keep them safe, since you will never see them again!",
- "greeting": "Welcome to Vibepollo!",
+ "create_creds_alert": "The credentials below are needed to access the Nimbus Web UI. Keep them safe, since you will never see them again!",
+ "greeting": "Welcome to Nimbus!",
"login": "Login",
"welcome_success": "This page will reload soon, your browser will ask you for the new credentials"
},
diff --git a/src_assets/common/assets/web/public/assets/locale/en_GB.json b/src_assets/common/assets/web/public/assets/locale/en_GB.json
index 505a5a8fe8..3093eafbf5 100644
--- a/src_assets/common/assets/web/public/assets/locale/en_GB.json
+++ b/src_assets/common/assets/web/public/assets/locale/en_GB.json
@@ -530,11 +530,11 @@
"ds5_inputtino_randomize_mac_desc": "Upon controller registration use a random MAC instead of one based on the controllers internal index to avoid mixing configuration settings of different controllers when the are swapped on client-side.",
"gamepad_ds5_manual": "DS5 selection options",
"vigem_missing_title": "Virtual Gamepad Driver (ViGEm) not installed",
- "vigem_missing_desc": "Vibepollo requires the ViGEmBus driver to emulate controllers on Windows. It is no longer bundled. Please download and install it manually:",
+ "vigem_missing_desc": "Nimbus requires the ViGEmBus driver to emulate controllers on Windows. It is no longer bundled. Please download and install it manually:",
"vigem_install": "Download ViGEmBus",
"vigem_detected_version": "Detected",
"crash_dump_title": "Recent crash detected",
- "crash_dump_desc": "Vibepollo detected a crash dump within the last week. Please export a crash bundle and include it when opening an issue.",
+ "crash_dump_desc": "Nimbus detected a crash dump within the last week. Please export a crash bundle and include it when opening an issue.",
"crash_dump_export": "Export Crash Bundle",
"crash_dump_report": "Report Issue",
"crash_dump_dismiss": "Dismiss",
@@ -611,16 +611,16 @@
"legacy_ordering_desc": "Enable ordering support workaround for legacy clients. Can cause issues with clients or scripts that can't handle UTF8 correctly. Artemis clients support this by default."
},
"index": {
- "description": "Vibepollo is a self-hosted game stream host for Moonlight.",
+ "description": "Nimbus is a self-hosted game stream host for Moonlight-compatible clients.",
"download": "Download",
- "installed_version_not_stable": "You are running a pre-release version of Vibepollo. You may experience bugs or other issues. Please report any issues you encounter. Thank you for helping to make Vibepollo a better software!",
+ "installed_version_not_stable": "You are running a pre-release version of Nimbus. You may experience bugs or other issues. Please report any issues you encounter. Thank you for helping to make Nimbus better!",
"loading_latest": "Loading latest release...",
"new_pre_release": "A new Pre-Release Version is Available!",
"new_stable": "A new Stable Version is Available!",
- "startup_errors": "Attention! Vibepollo detected these errors during startup. We STRONGLY RECOMMEND fixing them before streaming.",
- "version_dirty": "Thank you for helping to make Vibepollo a better software!",
- "version_latest": "You are running the latest version of Vibepollo",
- "welcome": "Hello, Vibepollo!"
+ "startup_errors": "Attention! Nimbus detected these errors during startup. We STRONGLY RECOMMEND fixing them before streaming.",
+ "version_dirty": "Thank you for helping to make Nimbus better!",
+ "version_latest": "You are running the latest version of Nimbus",
+ "welcome": "Hello, Nimbus!"
},
"navbar": {
"applications": "Applications",
@@ -680,7 +680,7 @@
"license": "License",
"lizardbyte_website": "LizardByte Website",
"resources": "Resources",
- "resources_desc": "Resources for Vibepollo!",
+ "resources_desc": "Resources for Nimbus!",
"third_party_notice": "Third Party Notice"
},
"troubleshooting": {
@@ -743,8 +743,8 @@
"welcome": {
"confirm_password": "Confirm password",
"create_creds": "Before Getting Started, we need you to make a new username and password for accessing the Web UI.",
- "create_creds_alert": "The credentials below are needed to access Vibepollo's Web UI. Keep them safe, since you will never see them again!",
- "greeting": "Welcome to Vibepollo!",
+ "create_creds_alert": "The credentials below are needed to access the Nimbus Web UI. Keep them safe, since you will never see them again!",
+ "greeting": "Welcome to Nimbus!",
"login": "Login",
"welcome_success": "This page will reload soon, your browser will ask you for the new credentials"
},
diff --git a/src_assets/common/assets/web/public/assets/locale/en_US.json b/src_assets/common/assets/web/public/assets/locale/en_US.json
index 96873a11f9..02004c9a70 100644
--- a/src_assets/common/assets/web/public/assets/locale/en_US.json
+++ b/src_assets/common/assets/web/public/assets/locale/en_US.json
@@ -533,11 +533,11 @@
"sudovda_status_watchdog_failed": "Watchdog failed",
"dd_resolution_option_manual_desc": "⚠️ Enforcing a manual resolution disables all display overrides below. The host will always be set to this resolution regardless of any override rules.",
"vigem_missing_title": "Virtual Gamepad Driver (ViGEm) not installed",
- "vigem_missing_desc": "Vibepollo requires the ViGEmBus driver to emulate controllers on Windows. It is no longer bundled. Please download and install it manually:",
+ "vigem_missing_desc": "Nimbus requires the ViGEmBus driver to emulate controllers on Windows. It is no longer bundled. Please download and install it manually:",
"vigem_install": "Download ViGEmBus",
"vigem_detected_version": "Detected",
"crash_dump_title": "Recent crash detected",
- "crash_dump_desc": "Vibepollo detected a crash dump within the last week. Please export a crash bundle and include it when opening an issue.",
+ "crash_dump_desc": "Nimbus detected a crash dump within the last week. Please export a crash bundle and include it when opening an issue.",
"crash_dump_export": "Export Crash Bundle",
"crash_dump_report": "Report Issue",
"crash_dump_dismiss": "Dismiss",
@@ -600,16 +600,16 @@
"legacy_ordering_desc": "Enable ordering support workaround for legacy clients. Can cause issues with clients or scripts that can't handle UTF8 correctly. Artemis clients support this by default."
},
"index": {
- "description": "Vibepollo is a self-hosted game stream host for Moonlight.",
+ "description": "Nimbus is a self-hosted game stream host for Moonlight-compatible clients.",
"download": "Download",
- "installed_version_not_stable": "You are running a pre-release version of Vibepollo. You may experience bugs or other issues. Please report any issues you encounter. Thank you for helping to make Vibepollo a better software!",
+ "installed_version_not_stable": "You are running a pre-release version of Nimbus. You may experience bugs or other issues. Please report any issues you encounter. Thank you for helping to make Nimbus better!",
"loading_latest": "Loading latest release...",
"new_pre_release": "A new Pre-Release Version is Available!",
"new_stable": "A new Stable Version is Available!",
- "startup_errors": "Attention! Vibepollo detected these errors during startup. We STRONGLY RECOMMEND fixing them before streaming.",
- "version_dirty": "Thank you for helping to make Vibepollo a better software!",
- "version_latest": "You are running the latest version of Vibepollo",
- "welcome": "Hello, Vibepollo!",
+ "startup_errors": "Attention! Nimbus detected these errors during startup. We STRONGLY RECOMMEND fixing them before streaming.",
+ "version_dirty": "Thank you for helping to make Nimbus better!",
+ "version_latest": "You are running the latest version of Nimbus",
+ "welcome": "Hello, Nimbus!",
"view_notes": "Release Notes",
"hide_notes": "Hide Notes",
"version_ahead": "You are running a development build ahead of the latest release ({ahead} commits)",
@@ -677,7 +677,7 @@
"lizardbyte_website": "LizardByte Website",
"resources": "Resources",
"discord_desc": "Join the community",
- "resources_desc": "Resources for Vibepollo!",
+ "resources_desc": "Resources for Nimbus!",
"third_party_notice": "Third Party Notice"
},
"troubleshooting": {
@@ -740,8 +740,8 @@
"welcome": {
"confirm_password": "Confirm password",
"create_creds": "Before Getting Started, we need you to make a new username and password for accessing the Web UI.",
- "create_creds_alert": "The credentials below are needed to access Vibepollo's Web UI. Keep them safe, since you will never see them again!",
- "greeting": "Welcome to Vibepollo!",
+ "create_creds_alert": "The credentials below are needed to access the Nimbus Web UI. Keep them safe, since you will never see them again!",
+ "greeting": "Welcome to Nimbus!",
"login": "Login",
"welcome_success": "This page will reload soon, your browser will ask you for the new credentials"
},
@@ -1184,6 +1184,5 @@
"sessions_time_unknown": "Unknown",
"sessions_unknown_device": "Unknown device",
"sessions_unknown_address": "Unknown address"
- "noticeCopy": "RTSS offers the most stable frame pacing. Vibepollo will use it automatically when available; NVIDIA's limiter is not recommended because it cannot guarantee perfect frame pacing."
}
}
diff --git a/src_assets/common/assets/web/views/DashboardView.vue b/src_assets/common/assets/web/views/DashboardView.vue
index 04d838ad26..e3d35c0cf6 100644
--- a/src_assets/common/assets/web/views/DashboardView.vue
+++ b/src_assets/common/assets/web/views/DashboardView.vue
@@ -135,7 +135,7 @@
{{
crashDumpMessage ||
$t('config.crash_dump_desc') ||
- 'Vibepollo detected a recent crash dump. Please export a crash bundle and include it when filing an issue.'
+ 'Nimbus detected a recent crash dump. Please export a crash bundle and include it when filing an issue.'
}}
@@ -199,7 +199,7 @@
{{
$t('config.vigem_missing_desc') ||
- 'Vibepollo requires the ViGEmBus driver to emulate controllers on Windows. It is no longer bundled. Please download and install it manually:'
+ 'Nimbus requires the ViGEmBus driver to emulate controllers on Windows. It is no longer bundled. Please download and install it manually:'
}}
({{ $t('config.vigem_detected_version') || 'Detected' }}: {{ vigemVersion }})
From fe7b74224d0b483a4e62ca2988519dd4ef611aa6 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 17:08:40 +1000
Subject: [PATCH 04/60] fix: retarget Windows visible branding to Nimbus
---
cmake/packaging/windows.cmake | 3 +--
packaging/windows/LICENSE.rtf | 2 +-
packaging/windows/bootstrapper/VibeshineInstaller.cs | 4 ++--
src/system_tray.cpp | 6 +++---
src_assets/common/assets/web/template_header.html | 2 +-
5 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/cmake/packaging/windows.cmake b/cmake/packaging/windows.cmake
index c5f2da38a4..d829e5c316 100644
--- a/cmake/packaging/windows.cmake
+++ b/cmake/packaging/windows.cmake
@@ -119,8 +119,7 @@ endif()
set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}\\\\apollo.ico")
# The name of the directory that will be created in C:/Program Files/
-# Match the legacy NSIS layout by installing under Apollo
-set(CPACK_PACKAGE_INSTALL_DIRECTORY "Apollo")
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "Nimbus")
# Setting components groups and dependencies
set(CPACK_COMPONENT_GROUP_CORE_EXPANDED true)
diff --git a/packaging/windows/LICENSE.rtf b/packaging/windows/LICENSE.rtf
index 73e23dc358..053276184d 100644
--- a/packaging/windows/LICENSE.rtf
+++ b/packaging/windows/LICENSE.rtf
@@ -1,6 +1,6 @@
{\rtf1\ansi\deff0
{\fonttbl{\f0\fswiss Helvetica;}}
-\viewkind4\uc1\pard\sa200\sl276\slmult1\f0\fs20 Vibepollo - Self-hosted game stream host for Moonlight.\par
+\viewkind4\uc1\pard\sa200\sl276\slmult1\f0\fs20 Nimbus - Self-hosted game stream host for Moonlight-compatible clients.\par
Copyright (C) 2025 Nonary\par
\par
This program is free software: you can redistribute it and/or modify\par
diff --git a/packaging/windows/bootstrapper/VibeshineInstaller.cs b/packaging/windows/bootstrapper/VibeshineInstaller.cs
index f66a1c8e54..e1be133d82 100644
--- a/packaging/windows/bootstrapper/VibeshineInstaller.cs
+++ b/packaging/windows/bootstrapper/VibeshineInstaller.cs
@@ -2151,7 +2151,7 @@ public static void WriteHelp() {
Console.WriteLine(" /?, /h, --help Show this help message");
Console.WriteLine();
Console.WriteLine("Supported MSI properties:");
- Console.WriteLine(" INSTALL_ROOT= Install to a custom directory (default: %ProgramFiles%\\Apollo)");
+ Console.WriteLine(" INSTALL_ROOT= Install to a custom directory (default: %ProgramFiles%\\Nimbus)");
Console.WriteLine(" INSTALL_SUDOVDA=0 Skip Virtual Display Driver installation");
Console.WriteLine();
Console.WriteLine("Examples:");
@@ -2279,7 +2279,7 @@ public static string DefaultInstallDirectory {
get {
return Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
- "Apollo");
+ ProductIdentity.Name);
}
}
diff --git a/src/system_tray.cpp b/src/system_tray.cpp
index 8561df45de..8b074998b7 100644
--- a/src/system_tray.cpp
+++ b/src/system_tray.cpp
@@ -138,7 +138,7 @@ namespace system_tray {
.menu =
(struct tray_menu[]) {
// todo - use boost/locale to translate menu strings
- {.text = "Open Apollo", .cb = tray_open_ui_cb},
+ {.text = "Open Nimbus", .cb = tray_open_ui_cb},
{.text = "-"},
// { .text = "-" },
// { .text = "Donate",
@@ -643,10 +643,10 @@ namespace system_tray {
}
#ifdef _WIN32
- std::string tmp_str = "Open Apollo (" + config::nvhttp.sunshine_name + ":" + std::to_string(net::map_port(confighttp::PORT_HTTPS)) + ")";
+ std::string tmp_str = "Open Nimbus (" + config::nvhttp.sunshine_name + ":" + std::to_string(net::map_port(confighttp::PORT_HTTPS)) + ")";
static const std::string title_str = utf8ToAcp(tmp_str);
#else
- static const std::string title_str = "Open Apollo (" + config::nvhttp.sunshine_name + ":" + std::to_string(net::map_port(confighttp::PORT_HTTPS)) + ")";
+ static const std::string title_str = "Open Nimbus (" + config::nvhttp.sunshine_name + ":" + std::to_string(net::map_port(confighttp::PORT_HTTPS)) + ")";
#endif
tray.menu[0].text = title_str.c_str();
diff --git a/src_assets/common/assets/web/template_header.html b/src_assets/common/assets/web/template_header.html
index c7560e4dac..e46c4fdf67 100644
--- a/src_assets/common/assets/web/template_header.html
+++ b/src_assets/common/assets/web/template_header.html
@@ -2,7 +2,7 @@
-Sunshine
+Nimbus
From f14d443bc9e6f49c1edc1389b804f51d9e702575 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 17:17:02 +1000
Subject: [PATCH 05/60] fix: harden Windows web package npm invocation
---
cmake/targets/common.cmake | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/cmake/targets/common.cmake b/cmake/targets/common.cmake
index 87013b8bd4..0e99257028 100644
--- a/cmake/targets/common.cmake
+++ b/cmake/targets/common.cmake
@@ -57,8 +57,18 @@ endif()
# Default layout: ${CMAKE_SOURCE_DIR}/src_assets/common/assets/web
set(WEB_UI_DIR "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web")
-#WebUI build
-find_program(NPM npm REQUIRED)
+# WebUI build. On Windows prefer the Node.js launcher from the standard
+# installer; MSYS npm can fail when invoked through cmd.exe during packaging.
+if(WIN32)
+ find_program(NPM npm.cmd
+ HINTS "$ENV{ProgramFiles}/nodejs"
+ NO_DEFAULT_PATH)
+ if(NOT NPM)
+ find_program(NPM NAMES npm.cmd npm REQUIRED)
+ endif()
+else()
+ find_program(NPM npm REQUIRED)
+endif()
set(NPM_INSTALL_FLAGS
--ignore-scripts
@@ -69,6 +79,7 @@ set(NPM_INSTALL_FLAGS
if (NPM_OFFLINE)
list(APPEND NPM_INSTALL_FLAGS --offline)
endif()
+set(NPM_CACHE_DIR "${CMAKE_BINARY_DIR}/npm-cache")
# Choose web UI build mode based on active CMake configuration.
# In Debug config, build Vite in "debug" mode to enable Vue devtools.
@@ -83,8 +94,11 @@ set(NPM_BUILD_NODE_OPTIONS "")
add_custom_target(web-ui ALL
WORKING_DIRECTORY "${WEB_UI_DIR}"
COMMENT "Installing NPM dependencies and building the Web UI"
- COMMAND "$<$:cmd;/C>" "${NPM}" ci ${NPM_INSTALL_FLAGS}
COMMAND "${CMAKE_COMMAND}" -E env
+ "NPM_CONFIG_CACHE=${NPM_CACHE_DIR}"
+ "$<$:cmd;/C>" "${NPM}" ci ${NPM_INSTALL_FLAGS}
+ COMMAND "${CMAKE_COMMAND}" -E env
+ "NPM_CONFIG_CACHE=${NPM_CACHE_DIR}"
"SUNSHINE_BUILD_HOMEBREW=${NPM_BUILD_HOMEBREW}"
"SUNSHINE_SOURCE_ASSETS_DIR=${NPM_SOURCE_ASSETS_DIR}"
"SUNSHINE_ASSETS_DIR=${NPM_ASSETS_DIR}"
From bea06db895f79dbd401398e9b8d8373d58a2ad05 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 17:18:36 +1000
Subject: [PATCH 06/60] docs: record Windows package revalidation blocker
---
docs/building.md | 9 +++++++
docs/release-build-audit.md | 50 +++++++++++++++++++++++++++++++++----
2 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/docs/building.md b/docs/building.md
index 5ead524a69..a8b2e5baec 100644
--- a/docs/building.md
+++ b/docs/building.md
@@ -120,6 +120,15 @@ The `package_installer` target uses CPack's WiX generator and requires WiX Tools
When building from MSYS2, configure CMake with Windows Git to keep generated version metadata clean:
`-DGIT_EXECUTABLE=C:/Progra~1/Git/cmd/git.exe`.
+On Windows, Nimbus prefers the standard Node.js `npm.cmd` launcher for the CMake web UI package step and stores npm
+cache data under the CMake build directory. If a build tree was configured before that change, clear the cached npm
+path before packaging:
+
+```powershell
+$env:PATH = 'C:\msys64\ucrt64\bin;' + $env:PATH
+cmake -S . -B build -UNPM
+```
+
##### WebRTC (optional, Windows only)
Nimbus can link against the libwebrtc C++ wrapper when `SUNSHINE_ENABLE_WEBRTC=ON`. The option name is inherited from
upstream and has not been renamed yet. The wrapper source is vendored as
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index 6d99036cfc..14163799d1 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -69,10 +69,11 @@ Applied hardening:
- Main release creation no longer closes `fixed` issues directly.
- The separate fixed-issue release closer is disabled.
-Remaining release blocker: package branding now emits Nimbus-named artifacts and
-the local Windows package build has verified the final installer output. A
-release tag is still blocked until installer execution is tested in a VM or
-snapshot fixture and release notes are prepared.
+Remaining release blocker: package branding now emits Nimbus-named artifacts,
+but the final package must be rebuilt from the current release-prep commit. A
+release tag is still blocked until the current package builds with WiX available,
+installer execution is tested in a VM or snapshot fixture, and release notes are
+prepared.
Decision: CI is safer for normal branch work and manual investigation, but do
not intentionally create a Nimbus release tag until package install, upgrade,
@@ -87,7 +88,7 @@ identity:
- `PROJECT_FQDN` is still `dev.lizardbyte.app.Sunshine`.
- `WINDOWS_APP_USER_MODEL_ID` is still `Nonary.Vibepollo`.
- CPack package name is now `Nimbus`.
-- Windows install directory is still `Apollo`.
+- Fresh Windows installs default to `Nimbus`.
- Windows WiX product family is seeded with `Vibepollo`.
- Bootstrapper text, support links, and output names now use Nimbus.
- Several installer paths intentionally detect or migrate Apollo and Sunshine.
@@ -173,6 +174,45 @@ Caveats:
- Signing and symbol publishing remain disabled until Nimbus-owned destinations
and secrets exist.
+## Local Windows Package Revalidation
+
+Validation date: 2026-05-21
+
+Validated commits: `ce9ec7aa`, `fe7b7422`, `f14d443b`
+
+Scope: revalidate the Nimbus release-safety, visible web branding, visible
+Windows branding, and CMake web packaging fixes after VM fixture feedback.
+
+Result:
+
+| Check | Result | Notes |
+| --- | --- | --- |
+| Web UI production build | Pass | `npm run build` passes after restoring dependencies. Vite still reports inherited large vendor chunk warnings. |
+| English locale JSON parse | Pass | `en.json`, `en_GB.json`, and repaired `en_US.json` parse successfully. |
+| Native Windows host build | Pass | `cmake --build build/nimbus-package-validation --target sunshine --config Release -j 6` passes when `C:\msys64\ucrt64\bin` is on `PATH`. |
+| Bootstrapper C# compile | Pass | `build_bootstrapper.ps1 -UninstallOnly` compiles the shared installer source. |
+| CMake package web step | Pass | Windows CMake now prefers `C:/Program Files/nodejs/npm.cmd` and uses a build-local npm cache. |
+| CPack WiX MSI | Blocked | Current host does not expose WiX v3 `candle.exe` / `light.exe`, so `package_installer` stops at CPack WiX. |
+
+Useful command shape:
+
+```powershell
+$env:PATH = 'C:\msys64\ucrt64\bin;' + $env:PATH
+cmake -S . -B build\nimbus-package-validation -UNPM
+cmake --build build\nimbus-package-validation --target package_installer --config Release -j 6
+```
+
+Current package blocker:
+
+```text
+Could not find the WiX candle executable.
+```
+
+Install WiX Toolset v3.14.1 or make its portable `bin` directory discoverable
+before rerunning the final package build. The old `82fa5cdd` artifacts above are
+historical validation evidence only; do not promote them as the current release
+candidate.
+
## Required Secrets Before Release CI
| Secret | Purpose | Current Risk |
From 2ab4bf9952028ff7aa49e36243ca0e4a00a3eebc Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 17:23:33 +1000
Subject: [PATCH 07/60] fix: rebrand hardcoded web copy to Nimbus
---
.../common/assets/web/Troubleshooting.vue | 6 +-
.../assets/web/components/AppEditModal.vue | 50 ++---
.../components/PlayniteReinstallButton.vue | 2 +-
.../app-edit/AppEditBasicsSection.vue | 6 +-
.../app-edit/AppEditFrameGenSection.vue | 16 +-
.../AppEditLosslessScalingSection.vue | 6 +-
.../assets/web/configs/tabs/Playnite.vue | 6 +-
.../tabs/audiovideo/DisplayDeviceOptions.vue | 2 +-
.../assets/web/public/assets/locale/en.json | 208 +++++++++---------
.../web/public/assets/locale/en_GB.json | 200 ++++++++---------
.../web/public/assets/locale/en_US.json | 200 ++++++++---------
11 files changed, 351 insertions(+), 351 deletions(-)
diff --git a/src_assets/common/assets/web/Troubleshooting.vue b/src_assets/common/assets/web/Troubleshooting.vue
index 90a2609d45..e9194baf50 100644
--- a/src_assets/common/assets/web/Troubleshooting.vue
+++ b/src_assets/common/assets/web/Troubleshooting.vue
@@ -55,7 +55,7 @@
{{
$t('troubleshooting.collect_playnite_logs_desc') ||
- 'Export Vibepollo, Playnite, plugin, and display-helper logs.'
+ 'Export Nimbus, Playnite, plugin, and display-helper logs.'
}}
@@ -74,7 +74,7 @@
{{
$t('troubleshooting.export_crash_bundle_desc') ||
- 'Download logs and the most recent Vibepollo crash dump for issue reports.'
+ 'Download logs and the most recent Nimbus crash dump for issue reports.'
}}
@@ -350,7 +350,7 @@ const tCount = (key: string, fallback: string, count: number) => {
const logSourceOptions = computed(() => {
const options = [
- { label: translate('troubleshooting.logs_source_sunshine', 'Vibepollo'), value: 'sunshine' },
+ { label: translate('troubleshooting.logs_source_sunshine', 'Nimbus'), value: 'sunshine' },
];
if (platform.value === 'windows') {
options.push(
diff --git a/src_assets/common/assets/web/components/AppEditModal.vue b/src_assets/common/assets/web/components/AppEditModal.vue
index 1ca01e6eb7..73ead4fcb3 100644
--- a/src_assets/common/assets/web/components/AppEditModal.vue
+++ b/src_assets/common/assets/web/components/AppEditModal.vue
@@ -2084,11 +2084,11 @@ async function refreshFrameGenHealth(options: FrameGenHealthOptions = {}): Promi
rtssRunning = !!data?.process_running;
if (rtssInstalled && rtssHooks) {
rtssStatus = 'pass';
- rtssMessage = 'RTSS hooks detected. Vibepollo can control the frame limiter.';
+ rtssMessage = 'RTSS hooks detected. Nimbus can control the frame limiter.';
} else if (rtssInstalled) {
rtssStatus = 'warn';
rtssMessage =
- 'RTSS is installed but hooks were not detected. Launch RTSS and ensure the Vibepollo profile is active.';
+ 'RTSS is installed but hooks were not detected. Launch RTSS and ensure the managed RTSS profile is active.';
} else {
rtssStatus = 'fail';
rtssMessage = 'Install RTSS to avoid microstutter when frame generation is enabled.';
@@ -2107,7 +2107,7 @@ async function refreshFrameGenHealth(options: FrameGenHealthOptions = {}): Promi
const tolerance = 0.5;
let displayStatus: FrameGenHealth['display']['status'] = 'unknown';
let displayMessage = 'Unable to determine display refresh capabilities.';
- let displayLabel = usingVirtual ? 'Vibepollo Virtual Screen' : 'Active display';
+ let displayLabel = usingVirtual ? 'Nimbus Virtual Screen' : 'Active display';
let displayId = usingVirtual ? VIRTUAL_DISPLAY_SELECTION : '';
let displayHz: number | null = null;
let displayError: string | null = null;
@@ -2268,55 +2268,55 @@ async function refreshFrameGenHealth(options: FrameGenHealthOptions = {}): Promi
displayStatus = 'pass';
if (only144Fails) {
const baseHz = hasActive ? (activeRefresh ?? evaluationHz) : evaluationHz;
- displayMessage = `Current refresh is ${Math.round(baseHz)} Hz. Streams up to 120 FPS are covered. Only 144 FPS streams require the Vibepollo virtual screen or a higher-refresh display.`;
+ displayMessage = `Current refresh is ${Math.round(baseHz)} Hz. Streams up to 120 FPS are covered. Only 144 FPS streams require the Nimbus virtual screen or a higher-refresh display.`;
if (!hasActive && highestSupported !== null) {
- displayMessage = `Display supports up to ${Math.round(highestSupported)} Hz. Streams up to 120 FPS are covered. Only 144 FPS streams require the Vibepollo virtual screen or a higher-refresh display.`;
+ displayMessage = `Display supports up to ${Math.round(highestSupported)} Hz. Streams up to 120 FPS are covered. Only 144 FPS streams require the Nimbus virtual screen or a higher-refresh display.`;
} else if (deltaSupported && highestSupported !== null) {
- displayMessage += ` Vibepollo can switch to ${Math.round(highestSupported)} Hz when a stream starts if Display Device Step 1 keeps that monitor active.`;
+ displayMessage += ` Nimbus can switch to ${Math.round(highestSupported)} Hz when a stream starts if Display Device Step 1 keeps that monitor active.`;
}
} else if (!hasActive && highestSupported !== null) {
- displayMessage = `Display supports up to ${Math.round(highestSupported)} Hz. Vibepollo can double 120 FPS streams.`;
+ displayMessage = `Display supports up to ${Math.round(highestSupported)} Hz. Nimbus can double 120 FPS streams.`;
} else if (deltaSupported && highestSupported !== null) {
- displayMessage = `Current refresh is ${Math.round(activeRefresh ?? evaluationHz)} Hz. Vibepollo can switch to ${Math.round(highestSupported)} Hz during streams to keep frame generation smooth.`;
+ displayMessage = `Current refresh is ${Math.round(activeRefresh ?? evaluationHz)} Hz. Nimbus can switch to ${Math.round(highestSupported)} Hz during streams to keep frame generation smooth.`;
} else {
displayMessage = 'Display refresh is high enough to double 120 FPS streams.';
}
} else if (evaluationHz >= 180 - tolerance) {
displayStatus = 'warn';
if (!hasActive && highestSupported !== null) {
- displayMessage = `Display supports up to ${Math.round(evaluationHz)} Hz. Configure Display Device Step 1 to enforce the higher refresh or use the display override below to switch to the Vibepollo virtual display.`;
+ displayMessage = `Display supports up to ${Math.round(evaluationHz)} Hz. Configure Display Device Step 1 to enforce the higher refresh or use the display override below to switch to the Nimbus virtual display.`;
} else if (hasActive) {
if (highestFailUnder144 !== null) {
- displayMessage = `Current refresh is ${Math.round(activeRefresh ?? evaluationHz)} Hz. Streams targeting up to ${highestFailUnder144} FPS need the Vibepollo virtual screen or a higher-refresh display.`;
+ displayMessage = `Current refresh is ${Math.round(activeRefresh ?? evaluationHz)} Hz. Streams targeting up to ${highestFailUnder144} FPS need the Nimbus virtual screen or a higher-refresh display.`;
} else {
- displayMessage = `Current refresh is ${Math.round(activeRefresh ?? evaluationHz)} Hz. 120 FPS frame generation may stutter without a higher refresh display. Use the display override below to switch to the Vibepollo virtual display or move the stream to a higher-refresh monitor.`;
+ displayMessage = `Current refresh is ${Math.round(activeRefresh ?? evaluationHz)} Hz. 120 FPS frame generation may stutter without a higher refresh display. Use the display override below to switch to the Nimbus virtual display or move the stream to a higher-refresh monitor.`;
}
if (deltaSupported && highestSupported !== null) {
- displayMessage += ` Vibepollo can switch up to ${Math.round(highestSupported)} Hz if Display Device Step 1 keeps only that monitor active.`;
+ displayMessage += ` Nimbus can switch up to ${Math.round(highestSupported)} Hz if Display Device Step 1 keeps only that monitor active.`;
}
} else {
displayMessage =
- 'Unable to read the current refresh rate, but the display may not reach the required 240 Hz. Use the display override below to switch to the Vibepollo virtual display or move the stream to a higher-refresh monitor.';
+ 'Unable to read the current refresh rate, but the display may not reach the required 240 Hz. Use the display override below to switch to the Nimbus virtual display or move the stream to a higher-refresh monitor.';
}
} else {
displayStatus = 'fail';
if (!hasActive && highestSupported !== null) {
- displayMessage = `Display tops out at ${Math.round(evaluationHz)} Hz. Use the display override below to switch to the Vibepollo virtual display or switch to a 240 Hz display for frame generation.`;
+ displayMessage = `Display tops out at ${Math.round(evaluationHz)} Hz. Use the display override below to switch to the Nimbus virtual display or switch to a 240 Hz display for frame generation.`;
} else if (hasActive) {
const mention = highestFailUnder144 ?? 120;
- displayMessage = `Current refresh is ${Math.round(activeRefresh ?? evaluationHz)} Hz. Streams targeting up to ${mention} FPS need the Vibepollo virtual screen or a higher-refresh display.`;
+ displayMessage = `Current refresh is ${Math.round(activeRefresh ?? evaluationHz)} Hz. Streams targeting up to ${mention} FPS need the Nimbus virtual screen or a higher-refresh display.`;
if (deltaSupported && highestSupported !== null) {
- displayMessage += ` Vibepollo can switch up to ${Math.round(highestSupported)} Hz if configured in Display Device Step 1.`;
+ displayMessage += ` Nimbus can switch up to ${Math.round(highestSupported)} Hz if configured in Display Device Step 1.`;
}
} else {
displayMessage =
- 'Display refresh information was unavailable. Use the display override below to switch to the Vibepollo virtual display or switch to a 240 Hz display for frame generation.';
+ 'Display refresh information was unavailable. Use the display override below to switch to the Nimbus virtual display or switch to a 240 Hz display for frame generation.';
}
}
} else {
displayStatus = 'unknown';
displayMessage =
- 'No display devices were returned by Vibepollo’s helper. Frame generation may not be able to enforce refresh changes.';
+ 'No display devices were returned by the Nimbus helper. Frame generation may not be able to enforce refresh changes.';
displayError = 'Display helper returned no devices.';
}
} else {
@@ -2332,7 +2332,7 @@ async function refreshFrameGenHealth(options: FrameGenHealthOptions = {}): Promi
} else {
displayStatus = 'pass';
displayMessage =
- 'Vibepollo virtual screen guarantees a high refresh surface for frame generation.';
+ 'Nimbus virtual screen guarantees a high refresh surface for frame generation.';
}
if (usingVirtual) {
@@ -2372,7 +2372,7 @@ async function refreshFrameGenHealth(options: FrameGenHealthOptions = {}): Promi
if (highestFailUnder144 !== null) {
health.suggestion = {
- message: `Use the display override above to switch to the Vibepollo virtual display or configure Display Device Step 1 to target the virtual display so ${highestFailUnder144} FPS streams stay smooth.`,
+ message: `Use the display override above to switch to the Nimbus virtual display or configure Display Device Step 1 to target the virtual display so ${highestFailUnder144} FPS streams stay smooth.`,
emphasis: 'warning',
};
} else if (captureStatus === 'warn' || captureStatus === 'fail') {
@@ -2443,7 +2443,7 @@ function warnIfHealthIssues(reason: FrameGenHealthReason) {
);
if (requiresHigh) {
message.warning(
- 'Use the display override to switch to the Vibepollo virtual display or adjust Display Device Step 1 to keep only the high-refresh monitor active.',
+ 'Use the display override to switch to the Nimbus virtual display or adjust Display Device Step 1 to keep only the high-refresh monitor active.',
{ duration: 8000 },
);
}
@@ -2538,18 +2538,18 @@ watch(
return;
}
message?.info(
- "Frame Generation Capture Fix requires Windows Graphics Capture (WGC), RTSS, and a display capable of 240 Hz or higher. Vibepollo's virtual screen or any display that satisfies the doubled refresh requirement will work.",
+ "Frame Generation Capture Fix requires Windows Graphics Capture (WGC), RTSS, and a display capable of 240 Hz or higher. Nimbus's virtual screen or any display that satisfies the doubled refresh requirement will work.",
{ duration: 8000 },
);
if (!skipDisplayWarnings.value) {
if (!ddConfigOption.value || ddConfigOption.value === 'disabled') {
message?.warning(
- 'Configure Step 1 for Vibepollo\'s virtual screen or enable Display Device and set it to "Deactivate all other displays" so the doubled refresh requirement is met during the stream.',
+ 'Configure Step 1 for Nimbus\'s virtual screen or enable Display Device and set it to "Deactivate all other displays" so the doubled refresh requirement is met during the stream.',
{ duration: 8000 },
);
} else if (ddConfigOption.value !== 'ensure_only_display') {
message?.warning(
- 'Set Step 1 to use Vibepollo\'s virtual screen or adjust Display Device to "Deactivate all other displays" so only the high-refresh monitor stays active.',
+ 'Set Step 1 to use Nimbus\'s virtual screen or adjust Display Device to "Deactivate all other displays" so only the high-refresh monitor stays active.',
{ duration: 8000 },
);
}
@@ -2738,7 +2738,7 @@ function onNamePicked(val: string | null) {
}
}
-// Cover preview logic removed; Vibepollo no longer fetches or proxies images
+// Cover preview logic removed; Nimbus no longer fetches or proxies images
async function save() {
saving.value = true;
try {
diff --git a/src_assets/common/assets/web/components/PlayniteReinstallButton.vue b/src_assets/common/assets/web/components/PlayniteReinstallButton.vue
index f12a48c9e8..620efd594b 100644
--- a/src_assets/common/assets/web/components/PlayniteReinstallButton.vue
+++ b/src_assets/common/assets/web/components/PlayniteReinstallButton.vue
@@ -68,7 +68,7 @@ const icon = props.icon ?? 'fas fa-plug';
const confirmTitle = props.confirmTitle ?? 'Install/Update Playnite Extension';
const confirmMessage =
props.confirmMessage ??
- 'This will (re)install the Vibepollo Playnite extension and restart Playnite if needed. Continue?';
+ 'This will (re)install the Nimbus Playnite extension and restart Playnite if needed. Continue?';
const cancelText = props.cancelText ?? 'Cancel';
const continueText = props.continueText ?? 'Continue';
const size = props.size ?? 'small';
diff --git a/src_assets/common/assets/web/components/app-edit/AppEditBasicsSection.vue b/src_assets/common/assets/web/components/app-edit/AppEditBasicsSection.vue
index 396cffa4f6..1afede3a0a 100644
--- a/src_assets/common/assets/web/components/app-edit/AppEditBasicsSection.vue
+++ b/src_assets/common/assets/web/components/app-edit/AppEditBasicsSection.vue
@@ -64,7 +64,7 @@
/>
- Vibepollo waits for this process. When it closes, the stream ends.
+ Nimbus waits for this process. When it closes, the stream ends.
@@ -115,7 +115,7 @@
placeholder="Command to execute before the stream"
/>
- Runs before the primary command. Vibepollo continues even if this command exits.
+ Runs before the primary command. Nimbus continues even if this command exits.
@@ -150,7 +150,7 @@
Find Cover
-
Optional; stored only and not fetched by Vibepollo.
- Select how Vibepollo coordinates frame generation and review the capture safeguards needed
+ Select how Nimbus coordinates frame generation and review the capture safeguards needed
for smooth playback.
@@ -211,7 +211,7 @@ const displayTargets = computed(() => props.health?.display.targets || []);
NVIDIA Smooth Motion active
- Vibepollo virtual screen in use
+ Nimbus virtual screen in use
- None keeps Vibepollo out of the loop, Game Provided trusts in-game frame generation,
+ None keeps Nimbus out of the loop, Game Provided trusts in-game frame generation,
Lossless Scaling wraps LSFG, and NVIDIA Smooth Motion configures the driver each launch.
- Use Vibepollo’s tuned profile or your Lossless Scaling defaults, then fine-tune
+ Use Nimbus’s tuned profile or your Lossless Scaling defaults, then fine-tune
the runtime targets.
- Vibepollo inherits the FPS your streaming client requests and forwards it to Lossless
+ Nimbus inherits the FPS your streaming client requests and forwards it to Lossless
Scaling automatically. When RTSS is available we cap it at half of that request for
steadier pacing.
- Vibepollo defaults to half of the client request when left blank. Requires RTSS
+ Nimbus defaults to half of the client request when left blank. Requires RTSS
installed and running.
- Enable Lossless Scaling when you want Vibepollo to manage upscaling before encoding.
+ Enable Lossless Scaling when you want Nimbus to manage upscaling before encoding.
@@ -19,7 +19,7 @@
size="small"
class="text-xs"
>
- This application isn't managed by Playnite. Vibepollo will try to guess which game executable
+ This application isn't managed by Playnite. Nimbus will try to guess which game executable
is running and apply the Lossless Scaling profile automatically, but that detection is
best-effort and may not always succeed. Configure Playnite integration for more reliable
results.
@@ -48,7 +48,7 @@
Custom: Use my Lossless Scaling default profile
- Recommended keeps Vibepollo-tuned values for consistent latency and frame pacing. Custom
+ Recommended keeps Nimbus-tuned values for consistent latency and frame pacing. Custom
runs the profile you maintain inside Lossless Scaling.
{{
$t('playnite.policy_explainer') ||
- 'Choose how Vibepollo removes old auto-synced games.'
+ 'Choose how Nimbus removes old auto-synced games.'
}}
@@ -355,7 +355,7 @@
:default="store.defaults.playnite_fullscreen_entry_enabled"
:localePrefix="'playnite'"
label="Add 'Playnite (Fullscreen)' to Applications"
- desc="When enabled, Vibepollo adds a launcher entry that opens Playnite in fullscreen desktop mode."
+ desc="When enabled, Nimbus adds a launcher entry that opens Playnite in fullscreen desktop mode."
/>
@@ -1362,7 +1362,7 @@ const policySummary = computed(() => {
if (syncAll) {
parts.push(
(t('playnite.summary_all_installed') as any) ||
- 'All installed Playnite games will be kept in Vibepollo.',
+ 'All installed Playnite games will be kept in Nimbus.',
);
} else if (includePluginCount > 0) {
parts.push(
diff --git a/src_assets/common/assets/web/configs/tabs/audiovideo/DisplayDeviceOptions.vue b/src_assets/common/assets/web/configs/tabs/audiovideo/DisplayDeviceOptions.vue
index e49b1899ac..89fa13c5b1 100644
--- a/src_assets/common/assets/web/configs/tabs/audiovideo/DisplayDeviceOptions.vue
+++ b/src_assets/common/assets/web/configs/tabs/audiovideo/DisplayDeviceOptions.vue
@@ -491,7 +491,7 @@ function clearSnapshotHotkey(): void {
Save a display snapshot (improves stability)
{{ $t('troubleshooting.dd_golden_help') }}
- Saving a snapshot of your ideal monitor setup helps Vibepollo recover when Windows
+ Saving a snapshot of your ideal monitor setup helps Nimbus recover when Windows
fails to restore displays after streaming.
diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json
index 940ec1946c..0b37263424 100644
--- a/src_assets/common/assets/web/public/assets/locale/en.json
+++ b/src_assets/common/assets/web/public/assets/locale/en.json
@@ -102,7 +102,7 @@
"global_prep_desc": "Enable/Disable the execution of Global Prep Commands for this application.",
"global_prep_name": "Global Prep Commands",
"image": "Image",
- "image_desc": "Application icon/picture/image path that will be sent to client. Image must be a PNG file. If not set, Vibepollo will send default box image.",
+ "image_desc": "Application icon/picture/image path that will be sent to client. Image must be a PNG file. If not set, Nimbus will send default box image.",
"loading": "Loading...",
"name": "Name",
"output_desc": "The file where the output of the command is stored, if it is not specified, the output is ignored",
@@ -111,18 +111,18 @@
"wait_all": "Continue streaming until all app processes exit",
"wait_all_desc": "This will continue streaming until all processes started by the app have terminated. When unchecked, streaming will stop when the initial app process exits, even if other app processes are still running.",
"working_dir": "Working Directory",
- "working_dir_desc": "The working directory that should be passed to the process. For example, some applications use the working directory to search for configuration files. If not set, Vibepollo will default to the parent directory of the command",
+ "working_dir_desc": "The working directory that should be passed to the process. For example, some applications use the working directory to search for configuration files. If not set, Nimbus will default to the parent directory of the command",
"more_fields_below": "More fields below — scroll"
},
"offline": {
- "title": "Lost Connection to Vibepollo",
- "description": "The web interface lost connectivity to the Vibepollo service.",
+ "title": "Lost Connection to Nimbus",
+ "description": "The web interface lost connectivity to the Nimbus service.",
"retrying": "Attempting to reconnect… The page will refresh once available.",
"refresh_now": "Refresh now",
- "close_hint": "If you stopped Vibepollo intentionally, you may close this tab.",
- "output_name_desc_unix": "During Vibepollo startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
- "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Vibepollo startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab.",
- "close_hint": "If you stopped Vibepollo intentionally, you may close this tab."
+ "close_hint": "If you stopped Nimbus intentionally, you may close this tab.",
+ "output_name_desc_unix": "During Nimbus startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
+ "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Nimbus startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab.",
+ "close_hint": "If you stopped Nimbus intentionally, you may close this tab."
},
"config": {
"amf": {
@@ -132,13 +132,13 @@
"adapter_name": "Adapter Name",
"adapter_name_desc_linux_1": "Manually specify a GPU to use for capture.",
"adapter_name_desc_linux_2": "to find all devices capable of VAAPI",
- "adapter_name_desc_linux_3": "Replace ``renderD129`` with the device from above to lists the name and capabilities of the device. To be supported by Vibepollo, it needs to have at the very minimum:",
+ "adapter_name_desc_linux_3": "Replace ``renderD129`` with the device from above to lists the name and capabilities of the device. To be supported by Nimbus, it needs to have at the very minimum:",
"adapter_name_desc_windows": "Manually specify a GPU to use for capture. If unset, the GPU is chosen automatically. We strongly recommend leaving this field blank to use automatic GPU selection! Note: This GPU must have a display connected and powered on. The appropriate values can be found using the following command:",
"adapter_name_placeholder_windows": "Radeon RX 580 Series",
"add": "Add",
"address_family": "Address Family",
"address_family_both": "IPv4+IPv6",
- "address_family_desc": "Set the address family used by Vibepollo",
+ "address_family_desc": "Set the address family used by Nimbus",
"address_family_ipv4": "IPv4 only",
"always_send_scancodes": "Always Send Scancodes",
"always_send_scancodes_desc": "Sending scancodes enhances compatibility with games and apps but may result in incorrect keyboard input from certain clients that aren't using a US English keyboard layout. Enable if keyboard input is not working at all in certain applications. Disable if keys on the client are generating the wrong input on the host.",
@@ -170,18 +170,18 @@
"amd_usage_webcam": "webcam -- webcam (slow)",
"amd_vbaq": "AMF Variance Based Adaptive Quantization (VBAQ)",
"amd_vbaq_desc": "The human visual system is typically less sensitive to artifacts in highly textured areas. In VBAQ mode, pixel variance is used to indicate the complexity of spatial textures, allowing the encoder to allocate more bits to smoother areas. Enabling this feature leads to improvements in subjective visual quality with some content.",
- "apply_note": "Click 'Apply' to restart Vibepollo and apply changes. This will terminate any running sessions.",
+ "apply_note": "Click 'Apply' to restart Nimbus and apply changes. This will terminate any running sessions.",
"audio_sink": "Audio Sink",
"audio_sink_desc_linux": "The name of the audio sink used for Audio Loopback. If you do not specify this variable, pulseaudio will select the default monitor device. You can find the name of the audio sink using either command:",
- "audio_sink_desc_macos": "The name of the audio sink used for Audio Loopback. Vibepollo can only access microphones on macOS due to system limitations. To stream system audio using Soundflower or BlackHole.",
+ "audio_sink_desc_macos": "The name of the audio sink used for Audio Loopback. Nimbus can only access microphones on macOS due to system limitations. To stream system audio using Soundflower or BlackHole.",
"audio_sink_desc_windows": "Manually specify a specific audio device to capture. If unset, the device is chosen automatically. We strongly recommend leaving this field blank to use automatic device selection! If you have multiple audio devices with identical names, you can get the Device ID using the following command:",
"audio_sink_placeholder_macos": "BlackHole 2ch",
"audio_sink_placeholder_windows": "Speakers (High Definition Audio Device)",
"av1_mode": "AV1 Support",
- "av1_mode_0": "Vibepollo will advertise support for AV1 based on encoder capabilities (recommended)",
- "av1_mode_1": "Vibepollo will not advertise support for AV1",
- "av1_mode_2": "Vibepollo will advertise support for AV1 Main 8-bit profile",
- "av1_mode_3": "Vibepollo will advertise support for AV1 Main 8-bit and 10-bit (HDR) profiles",
+ "av1_mode_0": "Nimbus will advertise support for AV1 based on encoder capabilities (recommended)",
+ "av1_mode_1": "Nimbus will not advertise support for AV1",
+ "av1_mode_2": "Nimbus will advertise support for AV1 Main 8-bit profile",
+ "av1_mode_3": "Nimbus will advertise support for AV1 Main 8-bit and 10-bit (HDR) profiles",
"av1_mode_desc": "Allows the client to request AV1 Main 8-bit or 10-bit video streams. AV1 is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.",
"prefer_10bit_sdr": "Prefer 10-bit SDR",
"prefer_10bit_sdr_follow_global": "Following the global 10-bit SDR setting.",
@@ -189,7 +189,7 @@
"back_button_timeout": "Home/Guide Button Emulation Timeout",
"back_button_timeout_desc": "If the Back/Select button is held down for the specified number of milliseconds, a Home/Guide button press is emulated. If set to a value < 0 (default), holding the Back/Select button will not emulate the Home/Guide button.",
"capture": "Force a Specific Capture Method",
- "capture_desc": "On automatic mode Vibepollo will use the first one that works. NvFBC requires patched nvidia drivers.",
+ "capture_desc": "On automatic mode Nimbus will use the first one that works. NvFBC requires patched nvidia drivers.",
"capture_auto_wgc": "Automatic (Windows Graphics Capture)",
"capture_wgc_auto": "Windows Graphics Capture (variable)",
"capture_ddx_legacy": "Desktop Duplication API (legacy)",
@@ -197,7 +197,7 @@
"cert": "Certificate",
"cert_desc": "The certificate used for the web UI and Moonlight client pairing. For best compatibility, this should have an RSA-2048 public key.",
"channels": "Maximum Connected Clients",
- "channels_desc_1": "Vibepollo can allow a single streaming session to be shared with multiple clients simultaneously.",
+ "channels_desc_1": "Nimbus can allow a single streaming session to be shared with multiple clients simultaneously.",
"channels_desc_2": "Some hardware encoders may have limitations that reduce performance with multiple streams.",
"coder_cabac": "cabac -- context adaptive binary arithmetic coding - higher quality",
"coder_cavlc": "cavlc -- context adaptive variable-length coding - faster decode",
@@ -205,7 +205,7 @@
"controller": "Enable Gamepad Input",
"controller_desc": "Allows guests to control the host system with a gamepad / controller",
"credentials_file": "Credentials File",
- "credentials_file_desc": "Store Username/Password separately from Vibepollo's state file.",
+ "credentials_file_desc": "Store Username/Password separately from Nimbus's state file.",
"dd_config_ensure_active": "Activate the display automatically",
"dd_config_ensure_active_warning": "Windows does not display the lock screen on external monitors until you click on them, which can cause black screens when streaming. If this is an issue, use the primary display option instead.",
"dd_config_ensure_only_display": "Deactivate other displays and activate only the specified display",
@@ -230,7 +230,7 @@
"golden_layout_upgrade_desc": "Your saved snapshot predates display layout support. Recreate it to restore portrait and landscape monitor layouts correctly.",
"golden_layout_upgrade_action": "Open Display Settings",
"dd_snapshot_restore_hotkey": "Restore snapshot hotkey",
- "dd_snapshot_restore_hotkey_desc": "Windows-only global hotkey. Useful for forcing virtual displays off and restoring snapshots when Vibepollo is paused or stuck. Click the field and press the combo you want.",
+ "dd_snapshot_restore_hotkey_desc": "Windows-only global hotkey. Useful for forcing virtual displays off and restoring snapshots when Nimbus is paused or stuck. Click the field and press the combo you want.",
"dd_snapshot_restore_hotkey_capture": "Listening... press a combo now.",
"dd_snapshot_restore_hotkey_reset": "Clear hotkey",
"dd_snapshot_restore_hotkey_invalid": "Unsupported key. Use F1-F24, letters, or digits.",
@@ -241,7 +241,7 @@
"dd_hdr_option_auto": "Switch on/off the HDR mode as requested by the client (default)",
"dd_hdr_option_disabled": "Do not change HDR settings",
"dd_wa_virtual_double_refresh": "Double refresh rate for virtual displays",
- "dd_wa_virtual_double_refresh_desc": "Creates Vibepollo virtual displays at 2x the target refresh to prevent unexplained FPS drops. Leave this on unless a specific game or monitor behaves incorrectly. Note: Manual refresh rate overrides this (no doubling).",
+ "dd_wa_virtual_double_refresh_desc": "Creates Nimbus virtual displays at 2x the target refresh to prevent unexplained FPS drops. Leave this on unless a specific game or monitor behaves incorrectly. Note: Manual refresh rate overrides this (no doubling).",
"dd_wa_dummy_plug_hdr10": "HDR 10-bit workaround for physical dummy plugs",
"dd_wa_dummy_plug_hdr10_desc": "Locks physical dummy plugs to 30 Hz and keeps the VSYNC override active so HDR10 is recognized. Only enable this when you are using a hardware dummy plug. Applied to game launches only (Desktop streams keep their normal refresh rate).",
"dd_wa_dummy_plug_hdr10_link": "Dummy Plugs setup guide",
@@ -262,7 +262,7 @@
"dd_mode_remapping_requested_resolution": "Requested resolution",
"dd_options_header": "Advanced display device options",
"dd_display_setup_title": "Display Setup (Before Stream)",
- "dd_display_setup_intro": "Choose the display to capture and how Vibepollo should prepare Windows just before a stream starts (turn on a monitor, switch primary, set resolution/refresh rate, HDR).",
+ "dd_display_setup_intro": "Choose the display to capture and how Nimbus should prepare Windows just before a stream starts (turn on a monitor, switch primary, set resolution/refresh rate, HDR).",
"dd_automation_label": "Display automation",
"dd_automation_desc": "Automatically adjust the host display to match the client's requested resolution and refresh rate before streaming.",
"dd_step_1": "Step 1",
@@ -275,17 +275,17 @@
"virtual_display_mode_per_client": "Virtual Display (Per Client)",
"virtual_display_mode_shared": "Shared Virtual Display",
"virtual_display_mode_label": "Virtual display mode",
- "virtual_display_mode_step_hint": "Select which display Vibepollo should prepare: keep your physical monitor, create a per-client virtual display, or reuse a shared virtual screen.",
+ "virtual_display_mode_step_hint": "Select which display Nimbus should prepare: keep your physical monitor, create a per-client virtual display, or reuse a shared virtual screen.",
"virtual_display_hdr_tip": "HDR Tip: Run Windows HDR Calibration while streaming and save the profile. Then open the Clients tab and click HDR Color Profile for the client to choose the saved profile.",
"virtual_display_layout_label": "Virtual Display Layout",
- "virtual_display_layout_hint": "Choose how Vibepollo positions and prioritizes your virtual display when it is enabled.",
+ "virtual_display_layout_hint": "Choose how Nimbus positions and prioritizes your virtual display when it is enabled.",
"virtual_display_toggle_label": "Configure Physical or Virtual Display",
- "virtual_display_toggle_hint": "Override the display Vibepollo uses for this app: switch to the Vibepollo virtual display or pick a specific physical monitor. Leave unchecked to follow the global/client choice.",
+ "virtual_display_toggle_hint": "Override the display Nimbus uses for this app: switch to the Nimbus virtual display or pick a specific physical monitor. Leave unchecked to follow the global/client choice.",
"app_display_override_label": "Per-app display override",
"client_display_override_label": "Per-client display override",
- "client_display_override_hint": "Override how Vibepollo chooses a display for this client. Leave unchecked to follow the global display settings.",
- "app_display_override_hint": "Choose whether this app should launch on the Vibepollo virtual display or target a specific physical monitor instead of the global default.",
- "app_display_override_virtual": "Use Vibepollo virtual display",
+ "client_display_override_hint": "Override how Nimbus chooses a display for this client. Leave unchecked to follow the global display settings.",
+ "app_display_override_hint": "Choose whether this app should launch on the Nimbus virtual display or target a specific physical monitor instead of the global default.",
+ "app_display_override_virtual": "Use Nimbus virtual display",
"app_display_override_physical": "Use a physical display",
"app_display_physical_label": "Select physical display",
"app_display_physical_hint": "Pick the monitor to use when launching this app. Physical dummy plugs show up here even if they are inactive.",
@@ -294,7 +294,7 @@
"app_display_status_active": "active",
"app_display_status_inactive": "inactive",
"virtual_display_layout_exclusive": "Exclusive",
- "virtual_display_layout_exclusive_desc": "Disable every other monitor so only the Vibepollo virtual display stays visible.",
+ "virtual_display_layout_exclusive_desc": "Disable every other monitor so only the Nimbus virtual display stays visible.",
"virtual_display_layout_extended": "Extended",
"virtual_display_layout_extended_desc": "Keep your physical monitors active and simply add the virtual display as another screen.",
"virtual_display_layout_extended_primary": "Extended + Primary",
@@ -303,10 +303,10 @@
"virtual_display_layout_extended_isolated_desc": "Extend the desktop but park the virtual display far away so the mouse never wanders into it.",
"virtual_display_layout_extended_primary_isolated": "Extended + Primary (Isolated)",
"virtual_display_layout_extended_primary_isolated_desc": "Combine primary + isolation: make the virtual display primary while keeping it out of reach of physical monitors.",
- "virtual_display_status_label": "Vibepollo virtual display driver:",
- "virtual_display_status_hint": "Use Vibepollo's virtual display to spin up a high-refresh virtual monitor automatically. If the driver reports an error, reinstall Vibepollo or repair the driver before streaming.",
+ "virtual_display_status_label": "Nimbus virtual display driver:",
+ "virtual_display_status_hint": "Use Nimbus's virtual display to spin up a high-refresh virtual monitor automatically. If the driver reports an error, reinstall Nimbus or repair the driver before streaming.",
"app_virtual_display_mode_label": "App display preference",
- "app_virtual_display_mode_hint": "When this app runs on the Vibepollo virtual display, choose whether to use a per-client or shared virtual screen and configure the layout below. Reset to follow the global display configuration.",
+ "app_virtual_display_mode_hint": "When this app runs on the Nimbus virtual display, choose whether to use a per-client or shared virtual screen and configure the layout below. Reset to follow the global display configuration.",
"app_virtual_display_mode_follow_global": "Following the global display configuration.",
"app_virtual_display_mode_reset": "Reset to global display",
"app_virtual_display_layout_reset": "Reset to global layout",
@@ -317,10 +317,10 @@
"sudovda_status_version_incompatible": "Driver version mismatch",
"sudovda_status_watchdog_failed": "Watchdog failed",
"dd_pre_stream_setup": "Pre-stream setup",
- "dd_pre_stream_intro": "Vibepollo applies these settings automatically when starting a stream. Use them to activate a display, make it primary, and optionally adjust resolution, refresh rate, and HDR.",
- "dd_config_hint": "Choose how Vibepollo prepares the display before streaming.",
- "dd_activate_virtual_display": "Auto-activate Vibepollo virtual display",
- "dd_activate_virtual_display_desc": "When using Vibepollo's virtual display driver, turn the virtual monitor on and temporarily make it the only active display while a stream is starting.",
+ "dd_pre_stream_intro": "Nimbus applies these settings automatically when starting a stream. Use them to activate a display, make it primary, and optionally adjust resolution, refresh rate, and HDR.",
+ "dd_config_hint": "Choose how Nimbus prepares the display before streaming.",
+ "dd_activate_virtual_display": "Auto-activate Nimbus virtual display",
+ "dd_activate_virtual_display_desc": "When using Nimbus's virtual display driver, turn the virtual monitor on and temporarily make it the only active display while a stream is starting.",
"dd_optional_adjustments": "Optional adjustments",
"dd_advanced_remapping_title": "Advanced: Mode remapping",
"dd_refresh_rate_option": "Refresh rate",
@@ -333,30 +333,30 @@
"dd_resolution_option_manual": "Use manually entered resolution",
"dd_resolution_option_manual_desc": "⚠️ Enforcing a manual resolution disables all display overrides below. The host will always be set to this resolution regardless of any override rules.",
"dd_refresh_rate_option_manual_desc": "⚠️ Enforcing a manual refresh rate forces the host to this refresh for all streams, overriding any refresh rules below and the \"Double refresh rate for virtual displays\" option.",
- "dd_wa_hdr_toggle_delay_desc_1": "When using virtual display device (VDD) for streaming, it might incorrectly display HDR color. Vibepollo can try to mitigate this issue, by turning HDR off and then on again.",
- "dd_wa_hdr_toggle_delay_desc_2": "If the value is set to 0, the workaround is disabled (default). If the value is between 0 and 3000 milliseconds, Vibepollo will turn off HDR, wait for the specified amount of time and then turn HDR on again. The recommended delay time is around 500 milliseconds in most cases.",
+ "dd_wa_hdr_toggle_delay_desc_1": "When using virtual display device (VDD) for streaming, it might incorrectly display HDR color. Nimbus can try to mitigate this issue, by turning HDR off and then on again.",
+ "dd_wa_hdr_toggle_delay_desc_2": "If the value is set to 0, the workaround is disabled (default). If the value is between 0 and 3000 milliseconds, Nimbus will turn off HDR, wait for the specified amount of time and then turn HDR on again. The recommended delay time is around 500 milliseconds in most cases.",
"dd_wa_hdr_toggle_delay_desc_3": "DO NOT use this workaround unless you actually have issues with HDR as it directly impacts stream start time!",
"dd_wa_hdr_toggle_delay": "High-contrast workaround for HDR",
"dd_wa_hdr_toggle": "High-contrast workaround for HDR",
- "dd_wa_hdr_toggle_desc": "When using a virtual display device (VDD), HDR colors can be wrong. Vibepollo can toggle HDR off and back on to mitigate this. Enable only if you see HDR color issues.",
+ "dd_wa_hdr_toggle_desc": "When using a virtual display device (VDD), HDR colors can be wrong. Nimbus can toggle HDR off and back on to mitigate this. Enable only if you see HDR color issues.",
"ds4_back_as_touchpad_click": "Map Back/Select to Touchpad Click",
"ds4_back_as_touchpad_click_desc": "When forcing DS4 emulation, map Back/Select to Touchpad Click",
"ds5_inputtino_randomize_mac": "Randomize virtual controller MAC",
"ds5_inputtino_randomize_mac_desc": "Upon controller registration use a random MAC instead of one based on the controllers internal index to avoid mixing configuration settings of different controllers when the are swapped on client-side.",
"encoder": "Force a Specific Encoder",
- "encoder_desc": "Force a specific encoder, otherwise Vibepollo will select the best available option. Note: If you specify a hardware encoder on Windows, it must match the GPU where the display is connected.",
+ "encoder_desc": "Force a specific encoder, otherwise Nimbus will select the best available option. Note: If you specify a hardware encoder on Windows, it must match the GPU where the display is connected.",
"encoder_software": "Software",
"external_ip": "External IP",
- "external_ip_desc": "If no external IP address is given, Vibepollo will automatically detect external IP",
+ "external_ip_desc": "If no external IP address is given, Nimbus will automatically detect external IP",
"fec_percentage": "FEC Percentage",
"fec_percentage_desc": "Percentage of error correcting packets per data packet in each video frame. Higher values can correct for more network packet loss, but at the cost of increasing bandwidth usage.",
"frame_limiter_fps_limit": "Frame limiter FPS limit",
"frame_limiter_fps_limit_desc": "Optional global FPS limit for the frame limiter. Set to 0 to use the stream's requested FPS.",
"ffmpeg_auto": "auto -- let ffmpeg decide (default)",
"file_apps": "Apps File",
- "file_apps_desc": "The file where current apps of Vibepollo are stored.",
+ "file_apps_desc": "The file where current apps of Nimbus are stored.",
"file_state": "State File",
- "file_state_desc": "The file where current state of Vibepollo is stored",
+ "file_state_desc": "The file where current state of Nimbus is stored",
"gamepad": "Emulated Gamepad Type",
"gamepad_auto": "Automatic selection options",
"gamepad_desc": "Choose which type of gamepad to emulate on the host",
@@ -384,13 +384,13 @@
"global_prep_cmd": "Command Preparations",
"global_prep_cmd_desc": "Configure a list of commands to be executed before or after running any application. If any of the specified preparation commands fail, the application launch process will be aborted.",
"hevc_mode": "HEVC Support",
- "hevc_mode_0": "Vibepollo will advertise support for HEVC based on encoder capabilities (recommended)",
- "hevc_mode_1": "Vibepollo will not advertise support for HEVC",
- "hevc_mode_2": "Vibepollo will advertise support for HEVC Main profile",
- "hevc_mode_3": "Vibepollo will advertise support for HEVC Main and Main10 (HDR) profiles",
+ "hevc_mode_0": "Nimbus will advertise support for HEVC based on encoder capabilities (recommended)",
+ "hevc_mode_1": "Nimbus will not advertise support for HEVC",
+ "hevc_mode_2": "Nimbus will advertise support for HEVC Main profile",
+ "hevc_mode_3": "Nimbus will advertise support for HEVC Main and Main10 (HDR) profiles",
"hevc_mode_desc": "Allows the client to request HEVC Main or HEVC Main10 video streams. HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.",
"high_resolution_scrolling": "High Resolution Scrolling Support",
- "high_resolution_scrolling_desc": "When enabled, Vibepollo will pass through high resolution scroll events from Moonlight clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
+ "high_resolution_scrolling_desc": "When enabled, Nimbus will pass through high resolution scroll events from Moonlight clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
"install_steam_audio_drivers": "Install Steam Audio Drivers",
"install_steam_audio_drivers_desc": "If Steam is installed, this will automatically install the Steam Streaming Speakers driver to support 5.1/7.1 surround sound and muting host audio.",
"key_repeat_delay": "Key Repeat Delay",
@@ -398,7 +398,7 @@
"key_repeat_frequency": "Key Repeat Frequency",
"key_repeat_frequency_desc": "How often keys repeat every second. This configurable option supports decimals.",
"key_rightalt_to_key_win": "Map Right Alt key to Windows key",
- "key_rightalt_to_key_win_desc": "It may be possible that you cannot send the Windows Key from Moonlight directly. In those cases it may be useful to make Vibepollo think the Right Alt key is the Windows key",
+ "key_rightalt_to_key_win_desc": "It may be possible that you cannot send the Windows Key from Moonlight directly. In those cases it may be useful to make Nimbus think the Right Alt key is the Windows key",
"keybindings": "Keybindings",
"keyboard": "Enable Keyboard Input",
"keyboard_desc": "Allows guests to control the host system with the keyboard",
@@ -407,11 +407,11 @@
"lan_encryption_mode_2": "Required for all clients",
"lan_encryption_mode_desc": "This determines when encryption will be used when streaming over your local network. Encryption can reduce streaming performance, particularly on less powerful hosts and clients.",
"locale": "Locale",
- "locale_desc": "The locale used for Vibepollo's user interface.",
+ "locale_desc": "The locale used for Nimbus's user interface.",
"log_path": "Logfile Path",
- "log_path_desc": "The file where the current logs of Vibepollo are stored.",
+ "log_path_desc": "The file where the current logs of Nimbus are stored.",
"max_bitrate": "Maximum Bitrate",
- "max_bitrate_desc": "The maximum bitrate (in Kbps) that Vibepollo will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.",
+ "max_bitrate_desc": "The maximum bitrate (in Kbps) that Nimbus will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.",
"minimum_fps_target": "Minimum FPS Target",
"minimum_fps_target_desc": "The lowest effective FPS a stream can reach. A value of 0 is treated as roughly half of the stream's FPS. A setting of 20 is recommended if you stream 24 or 30fps content.",
"session_token_ttl_seconds": "Web UI Session Timeout (seconds)",
@@ -441,17 +441,17 @@
"mouse": "Enable Mouse Input",
"mouse_desc": "Allows guests to control the host system with the mouse",
"native_pen_touch": "Native Pen/Touch Support",
- "native_pen_touch_desc": "When enabled, Vibepollo will pass through native pen/touch events from Moonlight clients. This can be useful to disable for older applications without native pen/touch support.",
+ "native_pen_touch_desc": "When enabled, Nimbus will pass through native pen/touch events from Moonlight clients. This can be useful to disable for older applications without native pen/touch support.",
"notify_pre_releases": "PreRelease Notifications",
- "notify_pre_releases_desc": "Whether to be notified of new pre-release versions of Vibepollo",
+ "notify_pre_releases_desc": "Whether to be notified of new pre-release versions of Nimbus",
"update_check_interval": "Update Check Interval (seconds)",
- "update_check_interval_desc": "How often Vibepollo should check for updates automatically (based on git tags). Set 0 to disable periodic checks.",
+ "update_check_interval_desc": "How often Nimbus should check for updates automatically (based on git tags). Set 0 to disable periodic checks.",
"nvenc_h264_cavlc": "Prefer CAVLC over CABAC in H.264",
"nvenc_h264_cavlc_desc": "Simpler form of entropy coding. CAVLC needs around 10% more bitrate for same quality. Only relevant for really old decoding devices.",
"nvenc_latency_over_power": "Prefer lower encoding latency over power savings",
- "nvenc_latency_over_power_desc": "Vibepollo requests maximum GPU clock speed while streaming to reduce encoding latency. Disabling it is not recommended since this can lead to significantly increased encoding latency.",
+ "nvenc_latency_over_power_desc": "Nimbus requests maximum GPU clock speed while streaming to reduce encoding latency. Disabling it is not recommended since this can lead to significantly increased encoding latency.",
"nvenc_opengl_vulkan_on_dxgi": "Present OpenGL/Vulkan on top of DXGI",
- "nvenc_opengl_vulkan_on_dxgi_desc": "Vibepollo can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted on sunshine program exit.",
+ "nvenc_opengl_vulkan_on_dxgi_desc": "Nimbus can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted on sunshine program exit.",
"nvenc_preset": "Performance preset",
"nvenc_preset_1": "(fastest, default)",
"nvenc_preset_4": "(balanced quality)",
@@ -478,8 +478,8 @@
"origin_web_ui_allowed_wan": "Anyone may access Web UI",
"output_name": "Display Id",
"output_name_default": "Primary display (default)",
- "output_name_desc_unix": "During Vibepollo startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
- "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Vibepollo startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab.",
+ "output_name_desc_unix": "During Nimbus startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
+ "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Nimbus startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab.",
"ping_timeout": "Ping Timeout",
"ping_timeout_desc": "How long to wait in milliseconds for data from moonlight before shutting down the stream",
"video_max_batch_size_kb": "Max Video Batch Size",
@@ -487,9 +487,9 @@
"pkey": "Private Key",
"pkey_desc": "The private key used for the web UI and Moonlight client pairing. For best compatibility, this should be an RSA-2048 private key.",
"port": "Port",
- "port_alert_1": "Vibepollo cannot use ports below 1024!",
+ "port_alert_1": "Nimbus cannot use ports below 1024!",
"port_alert_2": "Ports above 65535 are not available!",
- "port_desc": "Set the family of ports used by Vibepollo",
+ "port_desc": "Set the family of ports used by Nimbus",
"port_http_port_note": "Use this port to connect with Moonlight.",
"port_note": "Note",
"port_port": "Port",
@@ -516,13 +516,13 @@
"saving": "Saving…",
"saved_success": "Saved successfully",
"saved_deferred": "Changes will apply on next stream",
- "restart_required": "Restart Vibepollo to apply changes",
+ "restart_required": "Restart Nimbus to apply changes",
"manual_save_needed": "Manual save required (restart changes)",
"waiting_for_changes": "Waiting for changes…",
- "restart_note": "Vibepollo is restarting to apply changes.",
+ "restart_note": "Nimbus is restarting to apply changes.",
"stream_audio": "Stream Audio",
"stream_audio_desc": "Whether to stream audio or not. Disabling this can be useful for streaming headless displays as second monitors.",
- "sunshine_name": "Vibepollo Name",
+ "sunshine_name": "Nimbus Name",
"sunshine_name_desc": "The name displayed by Moonlight. If not specified, the PC's hostname is used",
"sw_preset": "SW Presets",
"sw_preset_desc": "Optimize the trade-off between encoding speed (encoded frames per second) and compression efficiency (quality per bit in the bitstream). Defaults to superfast.",
@@ -573,7 +573,7 @@
"lossless_scaling_legacy_auto_detect_desc": "Uses a timer-based auto-apply flow instead of the Lossless Scaling hotkey. Not recommended unless the hotkey method fails, because detection can be less reliable.",
"rtss_frame_limit_type": "RTSS frame limit type",
"rtss_install_path": "RTSS install path",
- "vibeshine_file_state": "Vibepollo state file",
+ "vibeshine_file_state": "Nimbus state file",
"virtual_display_layout": "Virtual display layout",
"virtual_display_mode": "Virtual display mode",
"dd_step_4": "Step 4",
@@ -598,7 +598,7 @@
"hide_tray_controls": "Hide tray control options",
"hide_tray_controls_desc": "Do not show \"Force Stop\", \"Restart\" and \"Quit\" in tray menu.",
"fallback_mode": "Fallback Display Mode",
- "fallback_mode_desc": "Vibepollo will use this mode when the client does not provide a mode or when the app is launched through the web UI. Format: [Width]x[Height]x[FPS]",
+ "fallback_mode_desc": "Nimbus will use this mode when the client does not provide a mode or when the app is launched through the web UI. Format: [Width]x[Height]x[FPS]",
"keep_sink_default": "Keep virtual sink as default",
"keep_sink_default_desc": "Leave the virtual audio sink selected as the default playback device while streaming audio is active.",
"auto_capture_sink": "Auto capture current sink",
@@ -728,7 +728,7 @@
"confirm_remove_title": "Remove Client",
"confirm_remove_message": "Are you sure you want to remove this client? It will need to be re-paired.",
"confirm_remove_title_named": "Remove Client \"{name}\"?",
- "confirm_remove_message_named": "This will unpair {name} from Vibepollo. They will need to pair again to connect.",
+ "confirm_remove_message_named": "This will unpair {name} from Nimbus. They will need to pair again to connect.",
"confirm_unpair_all_title": "Unpair All Clients",
"confirm_unpair_all_message": "Are you sure you want to unpair all clients? They will all need to be re-paired.",
"confirm_unpair_all_message_count": "This will unpair all {count} client(s). They will all need to pair again to connect.",
@@ -881,7 +881,7 @@
"chart_zoom_reset": "Reset zoom",
"chart_zoom_hint": "Scroll wheel to zoom · Shift+drag to pan",
"history_device": "Device",
- "history_server_version": "Vibepollo Version",
+ "history_server_version": "Nimbus Version",
"history_started": "Started",
"history_ended": "Ended",
"history_target_fps": "Target FPS",
@@ -918,7 +918,7 @@
"tip_history_device": "Hardware/OS device name reported by the client.",
"tip_history_app": "The Sunshine application that was launched for this session.",
"tip_history_duration": "How long the streaming session lasted from start to disconnect.",
- "tip_history_server_version": "Vibepollo version recorded when this stream started.",
+ "tip_history_server_version": "Nimbus version recorded when this stream started.",
"tip_history_bitrate": "The wire-bandwidth budget the client requested for this session. The encoder may have used slightly less after Sunshine subtracted FEC and audio overhead.",
"tip_chart_encode_latency": "How long the GPU/CPU spent encoding each frame, sampled every ~2 seconds. Consistently above 16ms means the encoder is struggling to keep up.",
"tip_chart_throughput": "Average outgoing video+audio bitrate in megabits per second, computed from byte deltas between samples. Should hover near the target bitrate.",
@@ -935,7 +935,7 @@
},
"playnite": {
"title": "Playnite Integration",
- "desc": "Vibepollo can sync your Playnite library so your installed games appear automatically. First, install Playnite, run it, and configure it to start with Windows. Then install the Vibepollo plugin below to enable the integration.",
+ "desc": "Nimbus can sync your Playnite library so your installed games appear automatically. First, install Playnite, run it, and configure it to start with Windows. Then install the Nimbus plugin below to enable the integration.",
"only_windows": "Playnite integration is available on Windows only.",
"status_title": "Plugin Status",
"status_overall": "Status",
@@ -945,7 +945,7 @@
"status_connected": "Connected",
"status_disabled": "Disabled",
"status_waiting": "Limited",
- "limited_tooltip": "Games cannot be auto-synced while Playnite is closed. Existing games added to Vibepollo will still work. Once you launch Playnite, syncing resumes automatically.",
+ "limited_tooltip": "Games cannot be auto-synced while Playnite is closed. Existing games added to Nimbus will still work. Once you launch Playnite, syncing resumes automatically.",
"refresh_status": "Refresh Status",
"maintenance_title": "Maintenance",
"copy_path": "Copy",
@@ -958,8 +958,8 @@
"status_not_running_unknown": "Playnite not running — plugin status unknown",
"status_unknown": "Playnite not detected",
"selects_disabled_hint": "Cannot modify without Playnite connectivity. Start Playnite to enable this.",
- "install_button": "Install Vibepollo Plugin",
- "reinstall_button": "Reinstall Vibepollo Plugin",
+ "install_button": "Install Nimbus Plugin",
+ "reinstall_button": "Reinstall Nimbus Plugin",
"upgrade_button": "Upgrade Plugin",
"uninstall_button": "Uninstall Plugin",
"uninstall_success": "Plugin uninstalled successfully.",
@@ -975,7 +975,7 @@
"plugin_outdated": "A newer Playnite plugin is available. Installed: v{installed}, Latest: v{latest}.",
"auto_sync": "Synchronize recently played games automatically",
"sync_all_installed": "Synchronize every installed Playnite game",
- "sync_all_installed_desc": "Adds every installed Playnite game to Vibepollo, alongside recent and category selections.",
+ "sync_all_installed_desc": "Adds every installed Playnite game to Nimbus, alongside recent and category selections.",
"enable_autosync_hint": "Enable synchronization to edit these settings.",
"recent_games": "Recent games to sync",
"recent_games_desc": "Maximum number of recent games to auto-sync. 0 = disable recent syncing.",
@@ -986,7 +986,7 @@
"cleanup_policy": "Cleanup Policy",
"policy_keep_until_replaced": "Keep until replaced (default)",
"policy_prune_immediately": "Always prune games that no longer qualify (may leave empty slots)",
- "policy_explainer": "Choose how Vibepollo removes old auto-synced games.",
+ "policy_explainer": "Choose how Nimbus removes old auto-synced games.",
"sync_categories": "Categories to sync",
"sync_categories_help": "Pick Playnite categories sync, which will add all games in that category regardless if they are recently played or not. This will not consume any recently played slot counts, it is simply appended to them.",
"sync_plugins": "Include library plugins",
@@ -999,7 +999,7 @@
"plugins_placeholder": "Pick library plugins to exclude",
"plugins_include_placeholder": "Include games from these plugins",
"remove_uninstalled": "Remove uninstalled games automatically",
- "remove_uninstalled_desc": "When enabled, Vibepollo removes auto-synced games as soon as they are uninstalled in Playnite.",
+ "remove_uninstalled_desc": "When enabled, Nimbus removes auto-synced games as soon as they are uninstalled in Playnite.",
"extensions_dir": "Extensions directory",
"install_dir": "Installation path override",
"save_success": "Settings saved.",
@@ -1045,7 +1045,7 @@
"summary_activity_ignored": "Activity window is ignored.",
"summary_keep_until_replaced": "Games stay until a newer game replaces them.",
"summary_prune_immediately": "Games are pruned when they no longer qualify.",
- "summary_all_installed": "All installed Playnite games are kept in Vibepollo.",
+ "summary_all_installed": "All installed Playnite games are kept in Nimbus.",
"summary_plugin_include": "Includes all games from {count} selected library plugins.",
"summary_remove_uninstalled_on": "Uninstalled games are removed automatically.",
"summary_remove_uninstalled_off": "Uninstalled games remain until you remove them manually.",
@@ -1064,7 +1064,7 @@
"pin": {
"device_name": "Device Name",
"display_mode_override": "Display mode override",
- "display_mode_override_desc": "Force Vibepollo to use this resolution and refresh rate for this client (format: 1920x1080x60). Leave blank to use the client's request.",
+ "display_mode_override_desc": "Force Nimbus to use this resolution and refresh rate for this client (format: 1920x1080x60). Leave blank to use the client's request.",
"pair_failure": "Pairing Failed: Check if the PIN is typed correctly",
"pair_success": "Success! Please check Moonlight to continue",
"pin_pairing": "PIN Pairing",
@@ -1101,7 +1101,7 @@
},
"troubleshooting": {
"dd_reset": "Reset Persistent Display Device Settings",
- "dd_reset_desc": "If Vibepollo is stuck trying to restore the changed display device settings, you can reset the settings and proceed to restore the display state manually.",
+ "dd_reset_desc": "If Nimbus is stuck trying to restore the changed display device settings, you can reset the settings and proceed to restore the display state manually.",
"dd_reset_error": "Error while resetting persistence!",
"dd_reset_success": "Success resetting persistence!",
"dd_export_golden": "Export Golden Display Restore",
@@ -1109,7 +1109,7 @@
"dd_export_golden_success": "Exported golden display snapshot.",
"dd_export_golden_error": "Failed to export golden display snapshot.",
"dd_golden_title": "Golden Display Restore",
- "dd_golden_help": "Save a snapshot of your current Windows display layout (which screens are on, primary display, resolution, HDR). Vibepollo uses this if your monitor settings don’t stick — for example after a reboot or at the sign‑in screen. This reduces the chance of coming back to a PC with the primary display still turned off.",
+ "dd_golden_help": "Save a snapshot of your current Windows display layout (which screens are on, primary display, resolution, HDR). Nimbus uses this if your monitor settings don’t stick — for example after a reboot or at the sign‑in screen. This reduces the chance of coming back to a PC with the primary display still turned off.",
"dd_golden_status_present": "Snapshot present",
"dd_golden_status_missing": "No snapshot found",
"dd_golden_create": "Create Snapshot",
@@ -1123,9 +1123,9 @@
"force_close_error": "Error while closing Application",
"force_close_success": "Application Closed Successfully!",
"logs": "Logs",
- "logs_desc": "See the logs uploaded by Vibepollo",
+ "logs_desc": "See the logs uploaded by Nimbus",
"logs_source": "Log source",
- "logs_source_sunshine": "Vibepollo",
+ "logs_source_sunshine": "Nimbus",
"logs_source_display_helper": "Display helper",
"logs_source_playnite": "Playnite",
"logs_source_playnite_launcher": "Playnite launcher",
@@ -1146,13 +1146,13 @@
"jump_to_latest": "Jump to latest logs",
"export_logs": "Export Logs",
"collect_playnite_logs": "Export Logs",
- "collect_playnite_logs_desc": "Export Vibepollo log, Playnite/plugin logs, and display-helper logs.",
+ "collect_playnite_logs_desc": "Export Nimbus log, Playnite/plugin logs, and display-helper logs.",
"export_crash_bundle": "Export Crash Bundle",
"export_crash_bundle_preparing": "Preparing Crash Bundle...",
- "export_crash_bundle_desc": "Download logs along with the most recent Vibepollo crash dump.",
- "restart_sunshine": "Restart Vibepollo",
- "restart_sunshine_desc": "If Vibepollo isn't working properly, you can try restarting it. This will terminate any running sessions.",
- "restart_sunshine_success": "Vibepollo is restarting",
+ "export_crash_bundle_desc": "Download logs along with the most recent Nimbus crash dump.",
+ "restart_sunshine": "Restart Nimbus",
+ "restart_sunshine_desc": "If Nimbus isn't working properly, you can try restarting it. This will terminate any running sessions.",
+ "restart_sunshine_success": "Nimbus is restarting",
"troubleshooting": "Troubleshooting",
"unpair_all": "Unpair All",
"unpair_all_error": "Error while unpairing",
@@ -1239,7 +1239,7 @@
"logout_refresh_hint": "You may now close this tab or refresh the page to sign back in.",
"logout_refresh_button": "Refresh to Sign In",
"sessions_heading": "Trusted Devices",
- "sessions_description": "Devices with active Vibepollo sessions. Remove entries to sign them out remotely.",
+ "sessions_description": "Devices with active Nimbus sessions. Remove entries to sign them out remotely.",
"sessions_device": "Device",
"sessions_activity": "Activity",
"sessions_status": "Status",
@@ -1264,9 +1264,9 @@
},
"rtss": {
"tab": "Frame Limiter",
- "desc": "Vibepollo can apply a global frame limit via RTSS (recommended) or NVIDIA Control Panel (experimental), then restores the original driver settings when streaming stops.",
+ "desc": "Nimbus can apply a global frame limit via RTSS (recommended) or NVIDIA Control Panel (experimental), then restores the original driver settings when streaming stops.",
"frame_limiter_disable_vsync": "Force VSYNC off while streaming",
- "frame_limiter_disable_vsync_desc": "When enabled, Vibepollo sets the NVIDIA driver VSYNC setting to Off for the duration of the stream and restores the previous value afterward. If NVIDIA overrides are unavailable, Vibepollo forces the display to run at its highest refresh rate as a best-effort fallback.",
+ "frame_limiter_disable_vsync_desc": "When enabled, Nimbus sets the NVIDIA driver VSYNC setting to Off for the duration of the stream and restores the previous value afterward. If NVIDIA overrides are unavailable, Nimbus forces the display to run at its highest refresh rate as a best-effort fallback.",
"frame_limiter_fps_limit": "Frame limiter FPS limit",
"frame_limiter_fps_limit_desc": "Optional global FPS limit for the frame limiter. Set to 0 to use the stream's requested FPS.",
"provider_label": "Frame limiter provider",
@@ -1296,9 +1296,9 @@
"install_path_placeholder": "C:\\Program Files (x86)\\RivaTuner Statistics Server",
"install_path_desc": "Root install folder (leave blank to auto-detect under Program Files / Program Files (x86)).",
"enable_frame_limiter": "Enable frame limiter",
- "enable_frame_limiter_desc": "When enabled, Vibepollo applies a global frame limit using your chosen provider for the duration of each stream, then restores the previous driver setting afterward.",
+ "enable_frame_limiter_desc": "When enabled, Nimbus applies a global frame limit using your chosen provider for the duration of each stream, then restores the previous driver setting afterward.",
"sync_limiter_mode": "SyncLimiter mode",
- "sync_limiter_desc": "Advanced users only. Vibepollo mirrors this into RTSS. See the comparison below before changing it.",
+ "sync_limiter_desc": "Advanced users only. Nimbus mirrors this into RTSS. See the comparison below before changing it.",
"sync_limiter_do_not_change": "Do not change",
"sync_limiter_async": "Async (recommended, eliminates microstuttering)",
"sync_limiter_front_edge": "Front edge sync",
@@ -1338,14 +1338,14 @@
"sync_limiter_reflex_use": "Only worth testing when Reflex is properly supported and tuned",
"recommend_title": "RTSS recommended",
"recommend_copy": "RTSS delivers the smoothest streaming experience. Install it if missing; NVIDIA's frame limiter is not recommended because it cannot guarantee perfect frame pacing.",
- "status_bootstrap": "RTSS detected; Vibepollo will refresh RTSS configuration on the next stream",
- "status_bootstrap_hint": "Vibepollo manages RTSS configuration automatically; no action needed.",
- "status_autolaunch_hint": "Vibepollo will launch RTSS automatically when streaming starts."
+ "status_bootstrap": "RTSS detected; Nimbus will refresh RTSS configuration on the next stream",
+ "status_bootstrap_hint": "Nimbus manages RTSS configuration automatically; no action needed.",
+ "status_autolaunch_hint": "Nimbus will launch RTSS automatically when streaming starts."
},
"frameLimiter": {
"stepTitle": "Frame pacing and limiter",
"enable": "Enable frame limiter",
- "enableHint": "Vibepollo applies the selected limiter provider at stream start and restores the previous driver setting when the stream ends.",
+ "enableHint": "Nimbus applies the selected limiter provider at stream start and restores the previous driver setting when the stream ends.",
"providerLabel": "Limiter provider",
"providerHint": "Auto prefers RTSS whenever it is available and falls back to the NVIDIA Control Panel limiter if needed. NVIDIA's limiter is not recommended because it cannot guarantee perfect frame pacing.",
"limitLabel": "FPS limit override",
@@ -1366,13 +1366,13 @@
},
"vsyncUllmLabel": "Disable VSYNC while streaming",
"vsyncUllmForcedByDummyPlug": "Forced on because the dummy plug HDR workaround requires VSYNC to be off for 10-bit output.",
- "vsyncUllmHintNv": "Vibepollo will force the NVIDIA driver VSYNC setting to Off during the stream and restore it afterward. Use this if you globally enable VSYNC but want Vibepollo sessions without it.",
- "vsyncUllmHintGeneric": "Vibepollo will run the display at its highest available refresh rate during the stream as a best-effort VSYNC workaround. NVIDIA overrides are not available on this system.",
+ "vsyncUllmHintNv": "Nimbus will force the NVIDIA driver VSYNC setting to Off during the stream and restore it afterward. Use this if you globally enable VSYNC but want Nimbus sessions without it.",
+ "vsyncUllmHintGeneric": "Nimbus will run the display at its highest available refresh rate during the stream as a best-effort VSYNC workaround. NVIDIA overrides are not available on this system.",
"rtssPath": "RTSS install path",
"rtssPathPlaceholder": "C:\\Program Files (x86)\\RivaTuner Statistics Server",
"rtssPathHint": "Root install folder (leave blank to auto-detect under Program Files / Program Files (x86)).",
"syncLimiterLabel": "RTSS SyncLimiter mode",
- "syncLimiterHint": "Optional: adjust RTSS SyncLimiter when Vibepollo uses RTSS to limit framerate.",
+ "syncLimiterHint": "Optional: adjust RTSS SyncLimiter when Nimbus uses RTSS to limit framerate.",
"rtssMissing": "RTSS was not detected. Install RTSS or adjust the install path to use it as a limiter.",
"status": {
"unknown": "Frame limiter status unavailable.",
@@ -1388,20 +1388,20 @@
"rtssDetected": "RTSS detected and ready.",
"rtssNotDetected": "RTSS not detected.",
"none": "None",
- "rtssBootstrap": "RTSS detected; Vibepollo will refresh RTSS configuration when streaming starts.",
- "rtssBootstrapHint": "Vibepollo manages RTSS configuration automatically; no action needed.",
- "rtssAutolaunchHint": "Vibepollo will launch RTSS automatically when a stream begins."
+ "rtssBootstrap": "RTSS detected; Nimbus will refresh RTSS configuration when streaming starts.",
+ "rtssBootstrapHint": "Nimbus manages RTSS configuration automatically; no action needed.",
+ "rtssAutolaunchHint": "Nimbus will launch RTSS automatically when a stream begins."
},
"actions": {
"refresh": "Refresh"
},
"noticeTitle": "RTSS recommended",
- "noticeCopy": "RTSS offers the most stable frame pacing. Vibepollo will use it automatically when available; NVIDIA's limiter is not recommended because it cannot guarantee perfect frame pacing."
+ "noticeCopy": "RTSS offers the most stable frame pacing. Nimbus will use it automatically when available; NVIDIA's limiter is not recommended because it cannot guarantee perfect frame pacing."
},
"changelog": {
"nav": "Changelog",
"title": "Changelog",
- "description": "Release notes for this installed Vibepollo build ({version}) and nearby releases.",
+ "description": "Release notes for this installed Nimbus build ({version}) and nearby releases.",
"installed": "Installed",
"latest_available": "Latest available",
"bundled_only": "Bundled notes only",
diff --git a/src_assets/common/assets/web/public/assets/locale/en_GB.json b/src_assets/common/assets/web/public/assets/locale/en_GB.json
index 3093eafbf5..7802ef2074 100644
--- a/src_assets/common/assets/web/public/assets/locale/en_GB.json
+++ b/src_assets/common/assets/web/public/assets/locale/en_GB.json
@@ -81,7 +81,7 @@
"global_prep_desc": "Enable/Disable the execution of Global Prep Commands for this application.",
"global_prep_name": "Global Prep Commands",
"image": "Image",
- "image_desc": "Application icon/picture/image path that will be sent to client. Image must be a PNG file. If not set, Vibepollo will send default box image.",
+ "image_desc": "Application icon/picture/image path that will be sent to client. Image must be a PNG file. If not set, Nimbus will send default box image.",
"loading": "Loading...",
"name": "Name",
"output_desc": "The file where the output of the command is stored, if it is not specified, the output is ignored",
@@ -111,19 +111,19 @@
"cannot_delete_autosync": "Auto-synced Playnite app cannot be deleted.",
"playnite_edit_notice": "This application is managed by Playnite. Command, Working Directory, and Detached commands are ignored. Prep commands still run before and after the game.",
"more_fields_below": "More fields below — scroll",
- "working_dir_desc": "The working directory that should be passed to the process. For example, some applications use the working directory to search for configuration files. If not set, Vibepollo will default to the parent directory of the command"
+ "working_dir_desc": "The working directory that should be passed to the process. For example, some applications use the working directory to search for configuration files. If not set, Nimbus will default to the parent directory of the command"
},
"config": {
"adapter_name": "Adapter Name",
"adapter_name_desc_linux_1": "Manually specify a GPU to use for capture.",
"adapter_name_desc_linux_2": "to find all devices capable of VAAPI",
- "adapter_name_desc_linux_3": "Replace ``renderD129`` with the device from above to lists the name and capabilities of the device. To be supported by Vibepollo, it needs to have at the very minimum:",
+ "adapter_name_desc_linux_3": "Replace ``renderD129`` with the device from above to lists the name and capabilities of the device. To be supported by Nimbus, it needs to have at the very minimum:",
"adapter_name_desc_windows": "Manually specify a GPU to use for capture. If unset, the GPU is chosen automatically. We strongly recommend leaving this field blank to use automatic GPU selection! Note: This GPU must have a display connected and powered on. The appropriate values can be found using the following command:",
"adapter_name_placeholder_windows": "Radeon RX 580 Series",
"add": "Add",
"address_family": "Address Family",
"address_family_both": "IPv4+IPv6",
- "address_family_desc": "Set the address family used by Vibepollo",
+ "address_family_desc": "Set the address family used by Nimbus",
"address_family_ipv4": "IPv4 only",
"always_send_scancodes": "Always Send Scancodes",
"always_send_scancodes_desc": "Sending scancodes enhances compatibility with games and apps but may result in incorrect keyboard input from certain clients that aren't using a US English keyboard layout. Enable if keyboard input is not working at all in certain applications. Disable if keys on the client are generating the wrong input on the host.",
@@ -155,18 +155,18 @@
"amd_usage_webcam": "webcam -- webcam (slow)",
"amd_vbaq": "AMF Variance Based Adaptive Quantization (VBAQ)",
"amd_vbaq_desc": "The human visual system is typically less sensitive to artifacts in highly textured areas. In VBAQ mode, pixel variance is used to indicate the complexity of spatial textures, allowing the encoder to allocate more bits to smoother areas. Enabling this feature leads to improvements in subjective visual quality with some content.",
- "apply_note": "Click 'Apply' to restart Vibepollo and apply changes. This will terminate any running sessions.",
+ "apply_note": "Click 'Apply' to restart Nimbus and apply changes. This will terminate any running sessions.",
"audio_sink": "Audio Sink",
"audio_sink_desc_linux": "The name of the audio sink used for Audio Loopback. If you do not specify this variable, pulseaudio will select the default monitor device. You can find the name of the audio sink using either command:",
- "audio_sink_desc_macos": "The name of the audio sink used for Audio Loopback. Vibepollo can only access microphones on macOS due to system limitations. To stream system audio using Soundflower or BlackHole.",
+ "audio_sink_desc_macos": "The name of the audio sink used for Audio Loopback. Nimbus can only access microphones on macOS due to system limitations. To stream system audio using Soundflower or BlackHole.",
"audio_sink_desc_windows": "Manually specify a specific audio device to capture. If unset, the device is chosen automatically. We strongly recommend leaving this field blank to use automatic device selection! If you have multiple audio devices with identical names, you can get the Device ID using the following command:",
"audio_sink_placeholder_macos": "BlackHole 2ch",
"audio_sink_placeholder_windows": "Speakers (High Definition Audio Device)",
"av1_mode": "AV1 Support",
- "av1_mode_0": "Vibepollo will advertise support for AV1 based on encoder capabilities (recommended)",
- "av1_mode_1": "Vibepollo will not advertise support for AV1",
- "av1_mode_2": "Vibepollo will advertise support for AV1 Main 8-bit profile",
- "av1_mode_3": "Vibepollo will advertise support for AV1 Main 8-bit and 10-bit (HDR) profiles",
+ "av1_mode_0": "Nimbus will advertise support for AV1 based on encoder capabilities (recommended)",
+ "av1_mode_1": "Nimbus will not advertise support for AV1",
+ "av1_mode_2": "Nimbus will advertise support for AV1 Main 8-bit profile",
+ "av1_mode_3": "Nimbus will advertise support for AV1 Main 8-bit and 10-bit (HDR) profiles",
"av1_mode_desc": "Allows the client to request AV1 Main 8-bit or 10-bit video streams. AV1 is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.",
"prefer_10bit_sdr": "Prefer 10-bit SDR",
"prefer_10bit_sdr_follow_global": "Following the global 10-bit SDR setting.",
@@ -174,7 +174,7 @@
"back_button_timeout": "Home/Guide Button Emulation Timeout",
"back_button_timeout_desc": "If the Back/Select button is held down for the specified number of milliseconds, a Home/Guide button press is emulated. If set to a value < 0 (default), holding the Back/Select button will not emulate the Home/Guide button.",
"capture": "Force a Specific Capture Method",
- "capture_desc": "On automatic mode Vibepollo will use the first one that works. NvFBC requires patched nvidia drivers.",
+ "capture_desc": "On automatic mode Nimbus will use the first one that works. NvFBC requires patched nvidia drivers.",
"capture_auto_wgc": "Automatic (Windows Graphics Capture)",
"capture_wgc_auto": "Windows Graphics Capture (variable)",
"capture_ddx_legacy": "Desktop Duplication API (legacy)",
@@ -184,7 +184,7 @@
"cert": "Certificate",
"cert_desc": "The certificate used for the web UI and Moonlight client pairing. For best compatibility, this should have an RSA-2048 public key.",
"channels": "Maximum Connected Clients",
- "channels_desc_1": "Vibepollo can allow a single streaming session to be shared with multiple clients simultaneously.",
+ "channels_desc_1": "Nimbus can allow a single streaming session to be shared with multiple clients simultaneously.",
"channels_desc_2": "Some hardware encoders may have limitations that reduce performance with multiple streams.",
"coder_cabac": "cabac -- context adaptive binary arithmetic coding - higher quality",
"coder_cavlc": "cavlc -- context adaptive variable-length coding - faster decode",
@@ -192,7 +192,7 @@
"controller": "Enable Gamepad Input",
"controller_desc": "Allows guests to control the host system with a gamepad / controller",
"credentials_file": "Credentials File",
- "credentials_file_desc": "Store Username/Password separately from Vibepollo's state file.",
+ "credentials_file_desc": "Store Username/Password separately from Nimbus's state file.",
"dd_config_ensure_active": "Activate the display automatically",
"dd_config_ensure_only_display": "Deactivate other displays and activate only the specified display",
"dd_config_ensure_primary": "Activate the display automatically and make it a primary display",
@@ -215,7 +215,7 @@
"dd_hdr_option_auto": "Switch on/off the HDR mode as requested by the client (default)",
"dd_hdr_option_disabled": "Do not change HDR settings",
"dd_wa_virtual_double_refresh": "Double refresh rate for virtual displays",
- "dd_wa_virtual_double_refresh_desc": "Creates Vibepollo virtual displays at 2x the target refresh to prevent unexplained FPS drops. Leave this on unless a specific game or monitor behaves incorrectly. Note: Manual refresh rate overrides this (no doubling).",
+ "dd_wa_virtual_double_refresh_desc": "Creates Nimbus virtual displays at 2x the target refresh to prevent unexplained FPS drops. Leave this on unless a specific game or monitor behaves incorrectly. Note: Manual refresh rate overrides this (no doubling).",
"dd_wa_dummy_plug_hdr10": "HDR 10-bit workaround for physical dummy plugs",
"dd_wa_dummy_plug_hdr10_desc": "Locks physical dummy plugs to 30 Hz and keeps the VSYNC override active so HDR10 is recognised. Only enable this when you are using a hardware dummy plug. Applied to game launches only (Desktop streams keep their normal refresh rate).",
"dd_wa_dummy_plug_hdr10_link": "Dummy Plugs setup guide",
@@ -233,7 +233,7 @@
"dd_mode_remapping_requested_resolution": "Stream resolution (requested)",
"dd_options_header": "Advanced display device options",
"dd_display_setup_title": "Display Setup (Before Stream)",
- "dd_display_setup_intro": "Choose the display to capture and how Vibepollo should prepare Windows just before a stream starts (turn on a monitor, switch primary, set resolution/refresh rate, HDR).",
+ "dd_display_setup_intro": "Choose the display to capture and how Nimbus should prepare Windows just before a stream starts (turn on a monitor, switch primary, set resolution/refresh rate, HDR).",
"dd_automation_label": "Display automation",
"dd_automation_desc": "Automatically adjust the host display to match the client's requested resolution and refresh rate before streaming.",
"dd_step_1": "Step 1",
@@ -243,15 +243,15 @@
"dd_virtual_display_choice_virtual": "Use virtualised display",
"dd_virtual_display_choice_physical": "Use my own display",
"app_virtual_display_mode_label": "App display preference",
- "app_virtual_display_mode_hint": "When this app runs on the Vibepollo virtual display, choose whether to use a per-client or shared virtual screen and configure the layout below. Reset to follow the global display configuration.",
+ "app_virtual_display_mode_hint": "When this app runs on the Nimbus virtual display, choose whether to use a per-client or shared virtual screen and configure the layout below. Reset to follow the global display configuration.",
"app_virtual_display_mode_follow_global": "Following the global display configuration.",
"app_virtual_display_mode_reset": "Reset to global display",
"app_virtual_display_layout_reset": "Reset to global layout",
"app_virtual_display_layout_follow_global": "Following the global virtual display layout.",
"app_display_override_label": "Per-app display override",
"client_display_override_label": "Client based override",
- "app_display_override_hint": "Choose whether this app should launch on the Vibepollo virtual display or target a specific physical monitor instead of the global default.",
- "app_display_override_virtual": "Use Vibepollo virtual display",
+ "app_display_override_hint": "Choose whether this app should launch on the Nimbus virtual display or target a specific physical monitor instead of the global default.",
+ "app_display_override_virtual": "Use Nimbus virtual display",
"app_display_override_physical": "Use a physical display",
"app_display_physical_label": "Select physical display",
"app_display_physical_hint": "Pick the monitor to use when launching this app. Physical dummy plugs show up here even if they are inactive.",
@@ -260,8 +260,8 @@
"app_display_status_active": "active",
"app_display_status_inactive": "inactive",
"dd_pre_stream_setup": "Pre-stream setup",
- "dd_pre_stream_intro": "Vibepollo applies these settings automatically when starting a stream. Use them to activate a display, make it primary, and optionally adjust resolution, refresh rate, and HDR.",
- "dd_config_hint": "Choose how Vibepollo prepares the display before streaming.",
+ "dd_pre_stream_intro": "Nimbus applies these settings automatically when starting a stream. Use them to activate a display, make it primary, and optionally adjust resolution, refresh rate, and HDR.",
+ "dd_config_hint": "Choose how Nimbus prepares the display before streaming.",
"dd_optional_adjustments": "Optional adjustments",
"dd_advanced_remapping_title": "Advanced: Mode remapping",
"dd_display_overrides": "Display overrides",
@@ -276,28 +276,28 @@
"dd_resolution_option_disabled": "Do not change resolution",
"dd_resolution_option_manual": "Use manually entered resolution",
"dd_resolution_option_manual_desc": "Enter the resolution to be used",
- "dd_wa_hdr_toggle_delay_desc_1": "When using virtual display device (VDD) for streaming, it might incorrectly display HDR color. Vibepollo can try to mitigate this issue, by turning HDR off and then on again.",
- "dd_wa_hdr_toggle_delay_desc_2": "If the value is set to 0, the workaround is disabled (default). If the value is between 0 and 3000 milliseconds, Vibepollo will turn off HDR, wait for the specified amount of time and then turn HDR on again. The recommended delay time is around 500 milliseconds in most cases.",
+ "dd_wa_hdr_toggle_delay_desc_1": "When using virtual display device (VDD) for streaming, it might incorrectly display HDR color. Nimbus can try to mitigate this issue, by turning HDR off and then on again.",
+ "dd_wa_hdr_toggle_delay_desc_2": "If the value is set to 0, the workaround is disabled (default). If the value is between 0 and 3000 milliseconds, Nimbus will turn off HDR, wait for the specified amount of time and then turn HDR on again. The recommended delay time is around 500 milliseconds in most cases.",
"dd_wa_hdr_toggle_delay_desc_3": "DO NOT use this workaround unless you actually have issues with HDR as it directly impacts stream start time!",
"dd_wa_hdr_toggle_delay": "High-contrast workaround for HDR",
"dd_wa_hdr_toggle": "High-contrast workaround for HDR",
- "dd_wa_hdr_toggle_desc": "When using a virtual display device (VDD), HDR colours can be wrong. Vibepollo can toggle HDR off and back on to mitigate this. Enable only if you see HDR colour issues.",
+ "dd_wa_hdr_toggle_desc": "When using a virtual display device (VDD), HDR colours can be wrong. Nimbus can toggle HDR off and back on to mitigate this. Enable only if you see HDR colour issues.",
"ds4_back_as_touchpad_click": "Map Back/Select to Touchpad Click",
"ds4_back_as_touchpad_click_desc": "When forcing DS4 emulation, map Back/Select to Touchpad Click",
"encoder": "Force a Specific Encoder",
- "encoder_desc": "Force a specific encoder, otherwise Vibepollo will select the best available option. Note: If you specify a hardware encoder on Windows, it must match the GPU where the display is connected.",
+ "encoder_desc": "Force a specific encoder, otherwise Nimbus will select the best available option. Note: If you specify a hardware encoder on Windows, it must match the GPU where the display is connected.",
"encoder_software": "Software",
"external_ip": "External IP",
- "external_ip_desc": "If no external IP address is given, Vibepollo will automatically detect external IP",
+ "external_ip_desc": "If no external IP address is given, Nimbus will automatically detect external IP",
"fec_percentage": "FEC Percentage",
"fec_percentage_desc": "Percentage of error correcting packets per data packet in each video frame. Higher values can correct for more network packet loss, but at the cost of increasing bandwidth usage.",
"frame_limiter_fps_limit": "Frame limiter FPS limit",
"frame_limiter_fps_limit_desc": "Optional global FPS limit for the frame limiter. Set to 0 to use the stream's requested FPS.",
"ffmpeg_auto": "auto -- let ffmpeg decide (default)",
"file_apps": "Apps File",
- "file_apps_desc": "The file where current apps of Vibepollo are stored.",
+ "file_apps_desc": "The file where current apps of Nimbus are stored.",
"file_state": "State File",
- "file_state_desc": "The file where current state of Vibepollo is stored",
+ "file_state_desc": "The file where current state of Nimbus is stored",
"gamepad": "Emulated Gamepad Type",
"gamepad_auto": "Automatic selection options",
"gamepad_desc": "Choose which type of gamepad to emulate on the host",
@@ -311,13 +311,13 @@
"global_prep_cmd": "Command Preparations",
"global_prep_cmd_desc": "Configure a list of commands to be executed before or after running any application. If any of the specified preparation commands fail, the application launch process will be aborted.",
"hevc_mode": "HEVC Support",
- "hevc_mode_0": "Vibepollo will advertise support for HEVC based on encoder capabilities (recommended)",
- "hevc_mode_1": "Vibepollo will not advertise support for HEVC",
- "hevc_mode_2": "Vibepollo will advertise support for HEVC Main profile",
- "hevc_mode_3": "Vibepollo will advertise support for HEVC Main and Main10 (HDR) profiles",
+ "hevc_mode_0": "Nimbus will advertise support for HEVC based on encoder capabilities (recommended)",
+ "hevc_mode_1": "Nimbus will not advertise support for HEVC",
+ "hevc_mode_2": "Nimbus will advertise support for HEVC Main profile",
+ "hevc_mode_3": "Nimbus will advertise support for HEVC Main and Main10 (HDR) profiles",
"hevc_mode_desc": "Allows the client to request HEVC Main or HEVC Main10 video streams. HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.",
"high_resolution_scrolling": "High Resolution Scrolling Support",
- "high_resolution_scrolling_desc": "When enabled, Vibepollo will pass through high resolution scroll events from Moonlight clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
+ "high_resolution_scrolling_desc": "When enabled, Nimbus will pass through high resolution scroll events from Moonlight clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
"install_steam_audio_drivers": "Install Steam Audio Drivers",
"install_steam_audio_drivers_desc": "If Steam is installed, this will automatically install the Steam Streaming Speakers driver to support 5.1/7.1 surround sound and muting host audio.",
"key_repeat_delay": "Key Repeat Delay",
@@ -325,7 +325,7 @@
"key_repeat_frequency": "Key Repeat Frequency",
"key_repeat_frequency_desc": "How often keys repeat every second. This configurable option supports decimals.",
"key_rightalt_to_key_win": "Map Right Alt key to Windows key",
- "key_rightalt_to_key_win_desc": "It may be possible that you cannot send the Windows Key from Moonlight directly. In those cases it may be useful to make Vibepollo think the Right Alt key is the Windows key",
+ "key_rightalt_to_key_win_desc": "It may be possible that you cannot send the Windows Key from Moonlight directly. In those cases it may be useful to make Nimbus think the Right Alt key is the Windows key",
"keyboard": "Enable Keyboard Input",
"keyboard_desc": "Allows guests to control the host system with the keyboard",
"lan_encryption_mode": "LAN Encryption Mode",
@@ -333,7 +333,7 @@
"lan_encryption_mode_2": "Required for all clients",
"lan_encryption_mode_desc": "This determines when encryption will be used when streaming over your local network. Encryption can reduce streaming performance, particularly on less powerful hosts and clients.",
"locale": "Locale",
- "locale_desc": "The locale used for Vibepollo's user interface.",
+ "locale_desc": "The locale used for Nimbus's user interface.",
"log_level": "Log Level",
"log_level_0": "Verbose",
"log_level_1": "Debug",
@@ -344,7 +344,7 @@
"log_level_6": "None",
"log_level_desc": "The minimum log level printed to standard out",
"log_path": "Logfile Path",
- "log_path_desc": "The file where the current logs of Vibepollo are stored.",
+ "log_path_desc": "The file where the current logs of Nimbus are stored.",
"session_token_ttl_seconds": "Web UI Session Timeout (seconds)",
"session_token_ttl_seconds_desc": "How long a Web UI login session remains valid before requiring re-authentication. Reduce for higher security; increase for convenience.",
"remember_me_refresh_token_ttl_seconds": "Trusted device lifetime (seconds)",
@@ -356,7 +356,7 @@
"session_history_db_size_limit_mb": "Session History DB Size Limit (MiB)",
"session_history_db_size_limit_mb_desc": "Approximate live size limit for the session history database. Oldest ended sessions are pruned when the database grows past this limit. Set 0 to disable size-based pruning.",
"max_bitrate": "Maximum Bitrate",
- "max_bitrate_desc": "The maximum bitrate (in Kbps) that Vibepollo will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.",
+ "max_bitrate_desc": "The maximum bitrate (in Kbps) that Nimbus will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.",
"min_threads": "Minimum CPU Thread Count",
"min_threads_desc": "Increasing the value slightly reduces encoding efficiency, but the tradeoff is usually worth it to gain the use of more CPU cores for encoding. The ideal value is the lowest value that can reliably encode at your desired streaming settings on your hardware.",
"misc": "Miscellaneous options",
@@ -365,15 +365,15 @@
"mouse": "Enable Mouse Input",
"mouse_desc": "Allows guests to control the host system with the mouse",
"native_pen_touch": "Native Pen/Touch Support",
- "native_pen_touch_desc": "When enabled, Vibepollo will pass through native pen/touch events from Moonlight clients. This can be useful to disable for older applications without native pen/touch support.",
+ "native_pen_touch_desc": "When enabled, Nimbus will pass through native pen/touch events from Moonlight clients. This can be useful to disable for older applications without native pen/touch support.",
"notify_pre_releases": "PreRelease Notifications",
- "notify_pre_releases_desc": "Whether to be notified of new pre-release versions of Vibepollo",
+ "notify_pre_releases_desc": "Whether to be notified of new pre-release versions of Nimbus",
"nvenc_h264_cavlc": "Prefer CAVLC over CABAC in H.264",
"nvenc_h264_cavlc_desc": "Simpler form of entropy coding. CAVLC needs around 10% more bitrate for same quality. Only relevant for really old decoding devices.",
"nvenc_latency_over_power": "Prefer lower encoding latency over power savings",
- "nvenc_latency_over_power_desc": "Vibepollo requests maximum GPU clock speed while streaming to reduce encoding latency. Disabling it is not recommended since this can lead to significantly increased encoding latency.",
+ "nvenc_latency_over_power_desc": "Nimbus requests maximum GPU clock speed while streaming to reduce encoding latency. Disabling it is not recommended since this can lead to significantly increased encoding latency.",
"nvenc_opengl_vulkan_on_dxgi": "Present OpenGL/Vulkan on top of DXGI",
- "nvenc_opengl_vulkan_on_dxgi_desc": "Vibepollo can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted on sunshine program exit.",
+ "nvenc_opengl_vulkan_on_dxgi_desc": "Nimbus can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted on sunshine program exit.",
"nvenc_preset": "Performance preset",
"nvenc_preset_1": "(fastest, default)",
"nvenc_preset_4": "(balanced quality)",
@@ -397,8 +397,8 @@
"origin_web_ui_allowed_lan": "Only those in LAN may access Web UI",
"origin_web_ui_allowed_pc": "Only localhost may access Web UI",
"origin_web_ui_allowed_wan": "Anyone may access Web UI",
- "output_name_desc_unix": "During Vibepollo startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis.",
- "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Vibepollo startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab.",
+ "output_name_desc_unix": "During Nimbus startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis.",
+ "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Nimbus startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab.",
"output_name_unix": "Display number",
"output_name_windows": "Display Device Id",
"ping_timeout": "Ping Timeout",
@@ -408,9 +408,9 @@
"pkey": "Private Key",
"pkey_desc": "The private key used for the web UI and Moonlight client pairing. For best compatibility, this should be an RSA-2048 private key.",
"port": "Port",
- "port_alert_1": "Vibepollo cannot use ports below 1024!",
+ "port_alert_1": "Nimbus cannot use ports below 1024!",
"port_alert_2": "Ports above 65535 are not available!",
- "port_desc": "Set the family of ports used by Vibepollo",
+ "port_desc": "Set the family of ports used by Nimbus",
"port_http_port_note": "Use this port to connect with Moonlight.",
"port_note": "Note",
"port_port": "Port",
@@ -432,10 +432,10 @@
"qsv_preset_veryfast": "fastest (lowest quality)",
"qsv_slow_hevc": "Allow Slow HEVC Encoding",
"qsv_slow_hevc_desc": "This can enable HEVC encoding on older Intel GPUs, at the cost of higher GPU usage and worse performance.",
- "restart_note": "Vibepollo is restarting to apply changes.",
+ "restart_note": "Nimbus is restarting to apply changes.",
"stream_audio": "Stream Audio",
"stream_audio_desc": "Whether to stream audio or not. Disabling this can be useful for streaming headless displays as second monitors.",
- "sunshine_name": "Vibepollo Name",
+ "sunshine_name": "Nimbus Name",
"sunshine_name_desc": "The name displayed by Moonlight. If not specified, the PC's hostname is used",
"sw_preset": "SW Presets",
"sw_preset_desc": "Optimize the trade-off between encoding speed (encoded frames per second) and compression efficiency (quality per bit in the bitstream). Defaults to superfast.",
@@ -488,7 +488,7 @@
"dd_snapshot_exclude_placeholder": "Choose devices (e.g., physical dummy plug) to exclude",
"dd_snapshot_exclude_warning": "Keep at least one display unexcluded.",
"dd_snapshot_restore_hotkey": "Restore snapshot hotkey",
- "dd_snapshot_restore_hotkey_desc": "Windows-only global hotkey. Useful for forcing virtual displays off and restoring snapshots when Vibepollo is paused or stuck. Click the field and press the combo you want.",
+ "dd_snapshot_restore_hotkey_desc": "Windows-only global hotkey. Useful for forcing virtual displays off and restoring snapshots when Nimbus is paused or stuck. Click the field and press the combo you want.",
"dd_snapshot_restore_hotkey_capture": "Listening... press a combo now.",
"dd_snapshot_restore_hotkey_reset": "Clear hotkey",
"dd_snapshot_restore_hotkey_invalid": "Unsupported key. Use F1-F24, letters, or digits.",
@@ -500,15 +500,15 @@
"virtual_display_mode_per_client": "Virtual Display (Per Client)",
"virtual_display_mode_shared": "Shared Virtual Display",
"virtual_display_mode_label": "Virtual display mode",
- "virtual_display_mode_step_hint": "Select which display Vibepollo should prepare: keep your physical monitor, create a per-client virtual display, or reuse a shared virtual screen.",
+ "virtual_display_mode_step_hint": "Select which display Nimbus should prepare: keep your physical monitor, create a per-client virtual display, or reuse a shared virtual screen.",
"virtual_display_hdr_tip": "HDR Tip: Run Windows HDR Calibration while streaming and save the profile. Then open the Clients tab and click HDR Color Profile for the client to choose the saved profile.",
"virtual_display_layout_label": "Virtual Display Layout",
- "virtual_display_layout_hint": "Choose how Vibepollo positions and prioritizes your virtual display when it is enabled.",
+ "virtual_display_layout_hint": "Choose how Nimbus positions and prioritizes your virtual display when it is enabled.",
"virtual_display_toggle_label": "Configure Physical or Virtual Display",
- "virtual_display_toggle_hint": "Override the display Vibepollo uses for this app: switch to the Vibepollo virtual display or pick a specific physical monitor. Leave unchecked to follow the global/client choice.",
- "client_display_override_hint": "Override how Vibepollo chooses a display for this client. Leave unchecked to follow the global display settings.",
+ "virtual_display_toggle_hint": "Override the display Nimbus uses for this app: switch to the Nimbus virtual display or pick a specific physical monitor. Leave unchecked to follow the global/client choice.",
+ "client_display_override_hint": "Override how Nimbus chooses a display for this client. Leave unchecked to follow the global display settings.",
"virtual_display_layout_exclusive": "Exclusive",
- "virtual_display_layout_exclusive_desc": "Disable every other monitor so only the Vibepollo virtual display stays visible.",
+ "virtual_display_layout_exclusive_desc": "Disable every other monitor so only the Nimbus virtual display stays visible.",
"virtual_display_layout_extended": "Extended",
"virtual_display_layout_extended_desc": "Keep your physical monitors active and simply add the virtual display as another screen.",
"virtual_display_layout_extended_primary": "Extended + Primary",
@@ -517,15 +517,15 @@
"virtual_display_layout_extended_isolated_desc": "Extend the desktop but park the virtual display far away so the mouse never wanders into it.",
"virtual_display_layout_extended_primary_isolated": "Extended + Primary (Isolated)",
"virtual_display_layout_extended_primary_isolated_desc": "Combine primary + isolation: make the virtual display primary while keeping it out of reach of physical monitors.",
- "virtual_display_status_label": "Vibepollo virtual display driver:",
- "virtual_display_status_hint": "Use Vibepollo's virtual display to spin up a high-refresh virtual monitor automatically. If the driver reports an error, reinstall Vibepollo or repair the driver before streaming.",
+ "virtual_display_status_label": "Nimbus virtual display driver:",
+ "virtual_display_status_hint": "Use Nimbus's virtual display to spin up a high-refresh virtual monitor automatically. If the driver reports an error, reinstall Nimbus or repair the driver before streaming.",
"sudovda_status_unknown": "Unknown",
"sudovda_status_ready": "Ready",
"sudovda_status_uninitialized": "Not initialized",
"sudovda_status_version_incompatible": "Driver version mismatch",
"sudovda_status_watchdog_failed": "Watchdog failed",
- "dd_activate_virtual_display": "Auto-activate Vibepollo virtual display",
- "dd_activate_virtual_display_desc": "When using Vibepollo's virtual display driver, turn the virtual monitor on and temporarily make it the only active display while a stream is starting.",
+ "dd_activate_virtual_display": "Auto-activate Nimbus virtual display",
+ "dd_activate_virtual_display_desc": "When using Nimbus's virtual display driver, turn the virtual monitor on and temporarily make it the only active display while a stream is starting.",
"ds5_inputtino_randomize_mac": "Randomize virtual controller MAC",
"ds5_inputtino_randomize_mac_desc": "Upon controller registration use a random MAC instead of one based on the controllers internal index to avoid mixing configuration settings of different controllers when the are swapped on client-side.",
"gamepad_ds5_manual": "DS5 selection options",
@@ -553,7 +553,7 @@
"min_log_level_6": "None",
"min_log_level_desc": "The minimum log level printed to standard out",
"update_check_interval": "Update Check Interval (seconds)",
- "update_check_interval_desc": "How often Vibepollo should check for updates automatically (based on git tags). Set 0 to disable periodic checks.",
+ "update_check_interval_desc": "How often Nimbus should check for updates automatically (based on git tags). Set 0 to disable periodic checks.",
"nvenc_section_title": "NVIDIA NVENC Encoder",
"output_name": "Display Id",
"hot_applied_now": "Settings saved and applied immediately.",
@@ -561,7 +561,7 @@
"saving": "Saving…",
"saved_success": "Saved successfully",
"saved_deferred": "Changes will apply on next stream",
- "restart_required": "Restart Vibepollo to apply changes",
+ "restart_required": "Restart Nimbus to apply changes",
"manual_save_needed": "Manual save required (restart changes)",
"waiting_for_changes": "Waiting for changes…",
"dd_hdr_request_override": "HDR request override",
@@ -572,7 +572,7 @@
"lossless_scaling_path": "Lossless Scaling executable",
"rtss_frame_limit_type": "RTSS frame limit type",
"rtss_install_path": "RTSS install path",
- "vibeshine_file_state": "Vibepollo state file",
+ "vibeshine_file_state": "Nimbus state file",
"virtual_display_layout": "Virtual display layout",
"virtual_display_mode": "Virtual display mode",
"adapter_name_placeholder_unix": "/dev/dri/renderD128",
@@ -596,7 +596,7 @@
"hide_tray_controls": "Hide tray control options",
"hide_tray_controls_desc": "Do not show \"Force Stop\", \"Restart\" and \"Quit\" in tray menu.",
"fallback_mode": "Fallback Display Mode",
- "fallback_mode_desc": "Vibepollo will use this mode when the client does not provide a mode or when the app is launched through the web UI. Format: [Width]x[Height]x[FPS]",
+ "fallback_mode_desc": "Nimbus will use this mode when the client does not provide a mode or when the app is launched through the web UI. Format: [Width]x[Height]x[FPS]",
"keep_sink_default": "Keep virtual sink as default",
"keep_sink_default_desc": "Leave the virtual audio sink selected as the default playback device while streaming audio is active.",
"auto_capture_sink": "Auto capture current sink",
@@ -653,7 +653,7 @@
"send": "Send",
"warning_msg": "Make sure you have access to the client you are pairing with. This software can give total control to your computer, so be careful!",
"display_mode_override": "Display mode override",
- "display_mode_override_desc": "Force Vibepollo to use this resolution and refresh rate for this client (format: 1920x1080x60). Leave blank to use the client's request."
+ "display_mode_override_desc": "Force Nimbus to use this resolution and refresh rate for this client (format: 1920x1080x60). Leave blank to use the client's request."
},
"permissions": {
"group_action": "Action",
@@ -685,7 +685,7 @@
},
"troubleshooting": {
"dd_reset": "Reset Persistent Display Device Settings",
- "dd_reset_desc": "If Vibepollo is stuck trying to restore the changed display device settings, you can reset the settings and proceed to restore the display state manually.",
+ "dd_reset_desc": "If Nimbus is stuck trying to restore the changed display device settings, you can reset the settings and proceed to restore the display state manually.",
"dd_reset_error": "Error while resetting persistence!",
"dd_reset_success": "Success resetting persistence!",
"dd_export_golden": "Export Golden Display Restore",
@@ -693,7 +693,7 @@
"dd_export_golden_success": "Exported golden display snapshot.",
"dd_export_golden_error": "Failed to export golden display snapshot.",
"dd_golden_title": "Golden Display Restore",
- "dd_golden_help": "Save a snapshot of your current Windows display layout (which screens are on, primary display, resolution, HDR). Vibepollo uses this if your monitor settings don’t stick — for example after a reboot or at the sign‑in screen. This reduces the chance of coming back to a PC with the primary display still turned off.",
+ "dd_golden_help": "Save a snapshot of your current Windows display layout (which screens are on, primary display, resolution, HDR). Nimbus uses this if your monitor settings don’t stick — for example after a reboot or at the sign‑in screen. This reduces the chance of coming back to a PC with the primary display still turned off.",
"dd_golden_status_present": "Snapshot present",
"dd_golden_status_missing": "No snapshot found",
"dd_golden_create": "Create Snapshot",
@@ -707,7 +707,7 @@
"force_close_error": "Error while closing Application",
"force_close_success": "Application Closed Successfully!",
"logs": "Logs",
- "logs_desc": "See the logs uploaded by Vibepollo",
+ "logs_desc": "See the logs uploaded by Nimbus",
"logs_find": "Find...",
"search_matches": "{count} matches",
"search_no_matches": "No matches",
@@ -719,9 +719,9 @@
"search_context": "{count} lines of context",
"search_line": "Line",
"jump_to_latest": "Jump to latest logs",
- "restart_sunshine": "Restart Vibepollo",
- "restart_sunshine_desc": "If Vibepollo isn't working properly, you can try restarting it. This will terminate any running sessions.",
- "restart_sunshine_success": "Vibepollo is restarting",
+ "restart_sunshine": "Restart Nimbus",
+ "restart_sunshine_desc": "If Nimbus isn't working properly, you can try restarting it. This will terminate any running sessions.",
+ "restart_sunshine_success": "Nimbus is restarting",
"troubleshooting": "Troubleshooting",
"unpair_all": "Unpair All",
"unpair_all_error": "Error while unpairing",
@@ -736,9 +736,9 @@
"new_logs_available": "New logs available — jump to latest",
"copy_logs": "Copy Logs",
"collect_playnite_logs": "Export Logs",
- "collect_playnite_logs_desc": "Export Vibepollo log, Playnite/plugin logs, and display-helper logs.",
+ "collect_playnite_logs_desc": "Export Nimbus log, Playnite/plugin logs, and display-helper logs.",
"export_crash_bundle": "Export Crash Bundle",
- "export_crash_bundle_desc": "Download logs along with the most recent Vibepollo crash dump."
+ "export_crash_bundle_desc": "Download logs along with the most recent Nimbus crash dump."
},
"welcome": {
"confirm_password": "Confirm password",
@@ -750,9 +750,9 @@
},
"rtss": {
"tab": "Frame Limiter",
- "desc": "Vibepollo can apply a global frame limit via NVIDIA Control Panel (default on NVIDIA GPUs) or RTSS, then restores the original setting when streaming stops.",
+ "desc": "Nimbus can apply a global frame limit via NVIDIA Control Panel (default on NVIDIA GPUs) or RTSS, then restores the original setting when streaming stops.",
"frame_limiter_disable_vsync": "Force VSYNC off while streaming",
- "frame_limiter_disable_vsync_desc": "When enabled, Vibepollo sets the NVIDIA driver VSYNC setting to Off for the duration of the stream and restores the previous value afterward. If NVIDIA overrides are unavailable, Vibepollo forces the display to run at its highest refresh rate as a best-effort fallback.",
+ "frame_limiter_disable_vsync_desc": "When enabled, Nimbus sets the NVIDIA driver VSYNC setting to Off for the duration of the stream and restores the previous value afterward. If NVIDIA overrides are unavailable, Nimbus forces the display to run at its highest refresh rate as a best-effort fallback.",
"frame_limiter_fps_limit": "Frame limiter FPS limit",
"frame_limiter_fps_limit_desc": "Optional global FPS limit for the frame limiter. Set to 0 to use the stream's requested FPS.",
"provider_label": "Frame limiter provider",
@@ -782,9 +782,9 @@
"install_path_placeholder": "C:\\Program Files (x86)\\RivaTuner Statistics Server",
"install_path_desc": "Root install folder (leave blank to auto-detect under Program Files / Program Files (x86)).",
"enable_frame_limiter": "Enable frame limiter",
- "enable_frame_limiter_desc": "When enabled, Vibepollo applies a global frame limit using your chosen provider for the duration of each stream, then restores the previous driver setting afterward.",
+ "enable_frame_limiter_desc": "When enabled, Nimbus applies a global frame limit using your chosen provider for the duration of each stream, then restores the previous driver setting afterward.",
"sync_limiter_mode": "SyncLimiter mode",
- "sync_limiter_desc": "Advanced users only. Vibepollo mirrors this into RTSS. See the comparison below before changing it.",
+ "sync_limiter_desc": "Advanced users only. Nimbus mirrors this into RTSS. See the comparison below before changing it.",
"sync_limiter_do_not_change": "Do not change",
"sync_limiter_async": "Async",
"sync_limiter_front_edge": "Front edge sync",
@@ -822,16 +822,16 @@
"sync_limiter_reflex_disadvantages": "Requires explicit game support; inconsistent behavior; microstutter issues are common",
"recommend_title": "RTSS recommended",
"recommend_copy": "RTSS delivers the smoothest streaming experience. Install it if missing; NVIDIA's frame limiter is not recommended because it cannot guarantee perfect frame pacing.",
- "status_bootstrap": "RTSS detected; Vibepollo will refresh RTSS configuration on the next stream",
- "status_bootstrap_hint": "Vibepollo manages RTSS configuration automatically; no action needed.",
- "status_autolaunch_hint": "Vibepollo will launch RTSS automatically when streaming starts.",
- "sync_limiter_reflex_stutter": "Can conflict with Vibepollo (microstutter likely)",
+ "status_bootstrap": "RTSS detected; Nimbus will refresh RTSS configuration on the next stream",
+ "status_bootstrap_hint": "Nimbus manages RTSS configuration automatically; no action needed.",
+ "status_autolaunch_hint": "Nimbus will launch RTSS automatically when streaming starts.",
+ "sync_limiter_reflex_stutter": "Can conflict with Nimbus (microstutter likely)",
"sync_limiter_reflex_use": "Only for testing when Reflex is mandatory"
},
"frameLimiter": {
"stepTitle": "Frame pacing and limiter",
"enable": "Enable frame limiter",
- "enableHint": "Vibepollo applies the selected limiter provider at stream start and restores the previous driver setting when the stream ends.",
+ "enableHint": "Nimbus applies the selected limiter provider at stream start and restores the previous driver setting when the stream ends.",
"providerLabel": "Limiter provider",
"providerHint": "Auto prefers NVIDIA Control Panel when available and falls back to RTSS otherwise.",
"limitLabel": "FPS limit override",
@@ -852,13 +852,13 @@
},
"vsyncUllmLabel": "Disable VSYNC while streaming",
"vsyncUllmForcedByDummyPlug": "Forced on because the dummy plug HDR workaround requires VSYNC to be off for 10-bit output.",
- "vsyncUllmHintNv": "Vibepollo will force the NVIDIA driver VSYNC setting to Off during the stream and restore it afterwards. Use this if you globally enable VSYNC but want Vibepollo sessions without it.",
- "vsyncUllmHintGeneric": "Vibepollo will run the display at its highest available refresh rate during the stream as a best-effort VSYNC workaround. NVIDIA overrides are not available on this system.",
+ "vsyncUllmHintNv": "Nimbus will force the NVIDIA driver VSYNC setting to Off during the stream and restore it afterwards. Use this if you globally enable VSYNC but want Nimbus sessions without it.",
+ "vsyncUllmHintGeneric": "Nimbus will run the display at its highest available refresh rate during the stream as a best-effort VSYNC workaround. NVIDIA overrides are not available on this system.",
"rtssPath": "RTSS install path",
"rtssPathPlaceholder": "C:\\Program Files (x86)\\RivaTuner Statistics Server",
"rtssPathHint": "Root install folder (leave blank to auto-detect under Program Files / Program Files (x86)).",
"syncLimiterLabel": "RTSS SyncLimiter mode",
- "syncLimiterHint": "Optional: adjust RTSS SyncLimiter when Vibepollo uses RTSS to limit framerate.",
+ "syncLimiterHint": "Optional: adjust RTSS SyncLimiter when Nimbus uses RTSS to limit framerate.",
"rtssMissing": "RTSS was not detected. Install RTSS or adjust the install path to use it as a limiter.",
"status": {
"unknown": "Frame limiter status unavailable.",
@@ -874,15 +874,15 @@
"rtssDetected": "RTSS detected.",
"rtssNotDetected": "RTSS not detected.",
"none": "None",
- "rtssBootstrap": "RTSS detected; Vibepollo will refresh RTSS configuration when streaming starts.",
- "rtssBootstrapHint": "Vibepollo manages RTSS configuration automatically; no action needed.",
- "rtssAutolaunchHint": "Vibepollo will launch RTSS automatically when a stream begins."
+ "rtssBootstrap": "RTSS detected; Nimbus will refresh RTSS configuration when streaming starts.",
+ "rtssBootstrapHint": "Nimbus manages RTSS configuration automatically; no action needed.",
+ "rtssAutolaunchHint": "Nimbus will launch RTSS automatically when a stream begins."
},
"actions": {
"refresh": "Refresh"
},
"noticeTitle": "RTSS recommended",
- "noticeCopy": "RTSS offers the most stable frame pacing. Vibepollo will use it automatically when available; NVIDIA's limiter is not recommended because it cannot guarantee perfect frame pacing."
+ "noticeCopy": "RTSS offers the most stable frame pacing. Nimbus will use it automatically when available; NVIDIA's limiter is not recommended because it cannot guarantee perfect frame pacing."
},
"playnite": {
"delete_all_autosync": "Delete All Playnite Auto-Sync Apps",
@@ -891,7 +891,7 @@
"delete_autosync_success": "Removed auto-synced Playnite games.",
"delete_autosync_error": "Failed to delete auto-synced Playnite games.",
"title": "Playnite Integration",
- "desc": "Vibepollo can sync your Playnite library so your installed games appear automatically. First, install Playnite, run it, and configure it to start with Windows. Then install the Vibepollo plugin below to enable the integration.",
+ "desc": "Nimbus can sync your Playnite library so your installed games appear automatically. First, install Playnite, run it, and configure it to start with Windows. Then install the Nimbus plugin below to enable the integration.",
"only_windows": "Playnite integration is available on Windows only.",
"status_title": "Plugin Status",
"status_overall": "Status",
@@ -901,7 +901,7 @@
"status_connected": "Connected",
"status_disabled": "Disabled",
"status_waiting": "Limited",
- "limited_tooltip": "Games cannot be auto-synced while Playnite is closed. Existing games added to Vibepollo will still work. Once you launch Playnite, syncing resumes automatically.",
+ "limited_tooltip": "Games cannot be auto-synced while Playnite is closed. Existing games added to Nimbus will still work. Once you launch Playnite, syncing resumes automatically.",
"refresh_status": "Refresh Status",
"maintenance_title": "Maintenance",
"copy_path": "Copy",
@@ -914,8 +914,8 @@
"status_not_running_unknown": "Playnite not running — plugin status unknown",
"status_unknown": "Playnite not detected",
"selects_disabled_hint": "Cannot modify without Playnite connectivity. Start Playnite to enable this.",
- "install_button": "Install Vibepollo Plugin",
- "reinstall_button": "Reinstall Vibepollo Plugin",
+ "install_button": "Install Nimbus Plugin",
+ "reinstall_button": "Reinstall Nimbus Plugin",
"upgrade_button": "Upgrade Plugin",
"uninstall_button": "Uninstall Plugin",
"uninstall_success": "Plugin uninstalled successfully.",
@@ -931,7 +931,7 @@
"plugin_outdated": "A newer Playnite plugin is available. Installed: v{installed}, Latest: v{latest}.",
"auto_sync": "Synchronize recently played games automatically",
"sync_all_installed": "Synchronize every installed Playnite game",
- "sync_all_installed_desc": "Adds every installed Playnite game to Vibepollo, alongside recent and category selections.",
+ "sync_all_installed_desc": "Adds every installed Playnite game to Nimbus, alongside recent and category selections.",
"enable_autosync_hint": "Enable synchronization to edit these settings.",
"recent_games": "Recent games to sync",
"recent_games_desc": "Maximum number of recent games to auto-sync. 0 = disable recent syncing.",
@@ -942,7 +942,7 @@
"cleanup_policy": "Cleanup Policy",
"policy_keep_until_replaced": "Keep until replaced (default)",
"policy_prune_immediately": "Always prune games that no longer qualify (may leave empty slots)",
- "policy_explainer": "Choose how Vibepollo removes old auto-synced games.",
+ "policy_explainer": "Choose how Nimbus removes old auto-synced games.",
"sync_categories": "Categories to sync",
"sync_categories_help": "Pick Playnite categories sync, which will add all games in that category regardless if they are recently played or not. This will not consume any recently played slot counts, it is simply appended to them.",
"sync_plugins": "Include library plugins",
@@ -955,7 +955,7 @@
"plugins_placeholder": "Pick library plugins to exclude",
"plugins_include_placeholder": "Include games from these plugins",
"remove_uninstalled": "Remove uninstalled games automatically",
- "remove_uninstalled_desc": "When enabled, Vibepollo removes auto-synced games as soon as they are uninstalled in Playnite.",
+ "remove_uninstalled_desc": "When enabled, Nimbus removes auto-synced games as soon as they are uninstalled in Playnite.",
"extensions_dir": "Extensions directory",
"install_dir": "Installation path override",
"save_success": "Settings saved.",
@@ -996,7 +996,7 @@
"summary_activity_ignored": "Activity window is ignored.",
"summary_keep_until_replaced": "Games stay until a newer game replaces them.",
"summary_prune_immediately": "Games are pruned when they no longer qualify.",
- "summary_all_installed": "All installed Playnite games are kept in Vibepollo.",
+ "summary_all_installed": "All installed Playnite games are kept in Nimbus.",
"summary_plugin_include": "Includes all games from {count} selected library plugins.",
"summary_remove_uninstalled_on": "Uninstalled games are removed automatically.",
"summary_remove_uninstalled_off": "Uninstalled games remain until you remove them manually.",
@@ -1005,13 +1005,13 @@
"summary_excluded_categories_more": "Excluded categories: {categories} (+{count} more)."
},
"offline": {
- "title": "Lost Connection to Vibepollo",
- "description": "The web interface lost connectivity to the Vibepollo service.",
+ "title": "Lost Connection to Nimbus",
+ "description": "The web interface lost connectivity to the Nimbus service.",
"retrying": "Attempting to reconnect… The page will refresh once available.",
"refresh_now": "Refresh now",
- "close_hint": "If you stopped Vibepollo intentionally, you may close this tab.",
- "output_name_desc_unix": "During Vibepollo startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
- "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Vibepollo startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab."
+ "close_hint": "If you stopped Nimbus intentionally, you may close this tab.",
+ "output_name_desc_unix": "During Nimbus startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
+ "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Nimbus startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab."
},
"resources": {
"title": "Resources"
@@ -1092,7 +1092,7 @@
"confirm_remove_title": "Remove Client",
"confirm_remove_message": "Are you sure you want to remove this client? It will need to be re-paired.",
"confirm_remove_title_named": "Remove Client \"{name}\"?",
- "confirm_remove_message_named": "This will unpair {name} from Vibepollo. They will need to pair again to connect.",
+ "confirm_remove_message_named": "This will unpair {name} from Nimbus. They will need to pair again to connect.",
"confirm_unpair_all_title": "Unpair All Clients",
"confirm_unpair_all_message": "Are you sure you want to unpair all clients? They will all need to be re-paired.",
"confirm_unpair_all_message_count": "This will unpair all {count} client(s). They will all need to pair again to connect."
@@ -1165,7 +1165,7 @@
"logout_refresh_hint": "You may now close this tab or refresh the page to sign back in.",
"logout_refresh_button": "Refresh to Sign In",
"sessions_heading": "Trusted Devices",
- "sessions_description": "Devices with active Vibepollo sessions. Remove entries to sign them out remotely.",
+ "sessions_description": "Devices with active Nimbus sessions. Remove entries to sign them out remotely.",
"sessions_device": "Device",
"sessions_activity": "Activity",
"sessions_status": "Status",
diff --git a/src_assets/common/assets/web/public/assets/locale/en_US.json b/src_assets/common/assets/web/public/assets/locale/en_US.json
index 02004c9a70..0d94d88b02 100644
--- a/src_assets/common/assets/web/public/assets/locale/en_US.json
+++ b/src_assets/common/assets/web/public/assets/locale/en_US.json
@@ -81,7 +81,7 @@
"global_prep_desc": "Enable/Disable the execution of Global Prep Commands for this application.",
"global_prep_name": "Global Prep Commands",
"image": "Image",
- "image_desc": "Application icon/picture/image path that will be sent to client. Image must be a PNG file. If not set, Vibepollo will send default box image.",
+ "image_desc": "Application icon/picture/image path that will be sent to client. Image must be a PNG file. If not set, Nimbus will send default box image.",
"loading": "Loading...",
"name": "Name",
"output_desc": "The file where the output of the command is stored, if it is not specified, the output is ignored",
@@ -111,19 +111,19 @@
"cannot_delete_autosync": "Auto-synced Playnite app cannot be deleted.",
"playnite_edit_notice": "This application is managed by Playnite. Command, Working Directory, and Detached commands are ignored. Prep commands still run before and after the game.",
"more_fields_below": "More fields below — scroll",
- "working_dir_desc": "The working directory that should be passed to the process. For example, some applications use the working directory to search for configuration files. If not set, Vibepollo will default to the parent directory of the command"
+ "working_dir_desc": "The working directory that should be passed to the process. For example, some applications use the working directory to search for configuration files. If not set, Nimbus will default to the parent directory of the command"
},
"config": {
"adapter_name": "Adapter Name",
"adapter_name_desc_linux_1": "Manually specify a GPU to use for capture.",
"adapter_name_desc_linux_2": "to find all devices capable of VAAPI",
- "adapter_name_desc_linux_3": "Replace ``renderD129`` with the device from above to lists the name and capabilities of the device. To be supported by Vibepollo, it needs to have at the very minimum:",
+ "adapter_name_desc_linux_3": "Replace ``renderD129`` with the device from above to lists the name and capabilities of the device. To be supported by Nimbus, it needs to have at the very minimum:",
"adapter_name_desc_windows": "Manually specify a GPU to use for capture. If unset, the GPU is chosen automatically. We strongly recommend leaving this field blank to use automatic GPU selection! Note: This GPU must have a display connected and powered on. The appropriate values can be found using the following command:",
"adapter_name_placeholder_windows": "Radeon RX 580 Series",
"add": "Add",
"address_family": "Address Family",
"address_family_both": "IPv4+IPv6",
- "address_family_desc": "Set the address family used by Vibepollo",
+ "address_family_desc": "Set the address family used by Nimbus",
"address_family_ipv4": "IPv4 only",
"always_send_scancodes": "Always Send Scancodes",
"always_send_scancodes_desc": "Sending scancodes enhances compatibility with games and apps but may result in incorrect keyboard input from certain clients that aren't using a US English keyboard layout. Enable if keyboard input is not working at all in certain applications. Disable if keys on the client are generating the wrong input on the host.",
@@ -155,18 +155,18 @@
"amd_usage_webcam": "webcam -- webcam (slow)",
"amd_vbaq": "AMF Variance Based Adaptive Quantization (VBAQ)",
"amd_vbaq_desc": "The human visual system is typically less sensitive to artifacts in highly textured areas. In VBAQ mode, pixel variance is used to indicate the complexity of spatial textures, allowing the encoder to allocate more bits to smoother areas. Enabling this feature leads to improvements in subjective visual quality with some content.",
- "apply_note": "Click 'Apply' to restart Vibepollo and apply changes. This will terminate any running sessions.",
+ "apply_note": "Click 'Apply' to restart Nimbus and apply changes. This will terminate any running sessions.",
"audio_sink": "Audio Sink",
"audio_sink_desc_linux": "The name of the audio sink used for Audio Loopback. If you do not specify this variable, pulseaudio will select the default monitor device. You can find the name of the audio sink using either command:",
- "audio_sink_desc_macos": "The name of the audio sink used for Audio Loopback. Vibepollo can only access microphones on macOS due to system limitations. To stream system audio using Soundflower or BlackHole.",
+ "audio_sink_desc_macos": "The name of the audio sink used for Audio Loopback. Nimbus can only access microphones on macOS due to system limitations. To stream system audio using Soundflower or BlackHole.",
"audio_sink_desc_windows": "Manually specify a specific audio device to capture. If unset, the device is chosen automatically. We strongly recommend leaving this field blank to use automatic device selection! If you have multiple audio devices with identical names, you can get the Device ID using the following command:",
"audio_sink_placeholder_macos": "BlackHole 2ch",
"audio_sink_placeholder_windows": "Speakers (High Definition Audio Device)",
"av1_mode": "AV1 Support",
- "av1_mode_0": "Vibepollo will advertise support for AV1 based on encoder capabilities (recommended)",
- "av1_mode_1": "Vibepollo will not advertise support for AV1",
- "av1_mode_2": "Vibepollo will advertise support for AV1 Main 8-bit profile",
- "av1_mode_3": "Vibepollo will advertise support for AV1 Main 8-bit and 10-bit (HDR) profiles",
+ "av1_mode_0": "Nimbus will advertise support for AV1 based on encoder capabilities (recommended)",
+ "av1_mode_1": "Nimbus will not advertise support for AV1",
+ "av1_mode_2": "Nimbus will advertise support for AV1 Main 8-bit profile",
+ "av1_mode_3": "Nimbus will advertise support for AV1 Main 8-bit and 10-bit (HDR) profiles",
"av1_mode_desc": "Allows the client to request AV1 Main 8-bit or 10-bit video streams. AV1 is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.",
"prefer_10bit_sdr": "Prefer 10-bit SDR",
"prefer_10bit_sdr_follow_global": "Following the global 10-bit SDR setting.",
@@ -174,7 +174,7 @@
"back_button_timeout": "Home/Guide Button Emulation Timeout",
"back_button_timeout_desc": "If the Back/Select button is held down for the specified number of milliseconds, a Home/Guide button press is emulated. If set to a value < 0 (default), holding the Back/Select button will not emulate the Home/Guide button.",
"capture": "Force a Specific Capture Method",
- "capture_desc": "On automatic mode Vibepollo will use the first one that works. NvFBC requires patched nvidia drivers.",
+ "capture_desc": "On automatic mode Nimbus will use the first one that works. NvFBC requires patched nvidia drivers.",
"capture_auto_wgc": "Automatic (Windows Graphics Capture)",
"capture_wgc_auto": "Windows Graphics Capture (variable)",
"capture_ddx_legacy": "Desktop Duplication API (legacy)",
@@ -184,7 +184,7 @@
"cert": "Certificate",
"cert_desc": "The certificate used for the web UI and Moonlight client pairing. For best compatibility, this should have an RSA-2048 public key.",
"channels": "Maximum Connected Clients",
- "channels_desc_1": "Vibepollo can allow a single streaming session to be shared with multiple clients simultaneously.",
+ "channels_desc_1": "Nimbus can allow a single streaming session to be shared with multiple clients simultaneously.",
"channels_desc_2": "Some hardware encoders may have limitations that reduce performance with multiple streams.",
"coder_cabac": "cabac -- context adaptive binary arithmetic coding - higher quality",
"coder_cavlc": "cavlc -- context adaptive variable-length coding - faster decode",
@@ -192,7 +192,7 @@
"controller": "Enable Gamepad Input",
"controller_desc": "Allows guests to control the host system with a gamepad / controller",
"credentials_file": "Credentials File",
- "credentials_file_desc": "Store Username/Password separately from Vibepollo's state file.",
+ "credentials_file_desc": "Store Username/Password separately from Nimbus's state file.",
"dd_config_ensure_active": "Activate the display automatically",
"dd_config_ensure_only_display": "Deactivate other displays and activate only the specified display",
"dd_config_ensure_primary": "Activate the display automatically and make it a primary display",
@@ -237,7 +237,7 @@
"dd_mode_remapping_requested_resolution": "Stream resolution (requested)",
"dd_options_header": "Advanced display device options",
"dd_display_setup_title": "Display Setup (Before Stream)",
- "dd_display_setup_intro": "Choose the display to capture and how Vibepollo should prepare Windows just before a stream starts (turn on a monitor, switch primary, set resolution/refresh rate, HDR).",
+ "dd_display_setup_intro": "Choose the display to capture and how Nimbus should prepare Windows just before a stream starts (turn on a monitor, switch primary, set resolution/refresh rate, HDR).",
"dd_automation_label": "Display automation",
"dd_automation_desc": "Automatically adjust the host display to match the client's requested resolution and refresh rate before streaming.",
"dd_step_1": "Step 1",
@@ -247,15 +247,15 @@
"dd_virtual_display_choice_virtual": "Use virtualized display",
"dd_virtual_display_choice_physical": "Use my own display",
"app_virtual_display_mode_label": "App display preference",
- "app_virtual_display_mode_hint": "When this app runs on the Vibepollo virtual display, choose whether to use a per-client or shared virtual screen and configure the layout below. Reset to follow the global display configuration.",
+ "app_virtual_display_mode_hint": "When this app runs on the Nimbus virtual display, choose whether to use a per-client or shared virtual screen and configure the layout below. Reset to follow the global display configuration.",
"app_virtual_display_mode_follow_global": "Following the global display configuration.",
"app_virtual_display_mode_reset": "Reset to global display",
"app_virtual_display_layout_reset": "Reset to global layout",
"app_virtual_display_layout_follow_global": "Following the global virtual display layout.",
"app_display_override_label": "Per-app display override",
"client_display_override_label": "Client based override",
- "app_display_override_hint": "Choose whether this app should launch on the Vibepollo virtual display or target a specific physical monitor instead of the global default.",
- "app_display_override_virtual": "Use Vibepollo virtual display",
+ "app_display_override_hint": "Choose whether this app should launch on the Nimbus virtual display or target a specific physical monitor instead of the global default.",
+ "app_display_override_virtual": "Use Nimbus virtual display",
"app_display_override_physical": "Use a physical display",
"app_display_physical_label": "Select physical display",
"app_display_physical_hint": "Pick the monitor to use when launching this app. Physical dummy plugs show up here even if they are inactive.",
@@ -264,10 +264,10 @@
"app_display_status_active": "active",
"app_display_status_inactive": "inactive",
"dd_pre_stream_setup": "Pre-stream setup",
- "dd_pre_stream_intro": "Vibepollo applies these settings automatically when starting a stream. Use them to activate a display, make it primary, and optionally adjust resolution, refresh rate, and HDR.",
- "dd_config_hint": "Choose how Vibepollo prepares the display before streaming.",
- "dd_activate_virtual_display": "Auto-activate Vibepollo virtual display",
- "dd_activate_virtual_display_desc": "When using Vibepollo's virtual display driver, turn the virtual monitor on and temporarily make it the only active display while a stream is starting.",
+ "dd_pre_stream_intro": "Nimbus applies these settings automatically when starting a stream. Use them to activate a display, make it primary, and optionally adjust resolution, refresh rate, and HDR.",
+ "dd_config_hint": "Choose how Nimbus prepares the display before streaming.",
+ "dd_activate_virtual_display": "Auto-activate Nimbus virtual display",
+ "dd_activate_virtual_display_desc": "When using Nimbus's virtual display driver, turn the virtual monitor on and temporarily make it the only active display while a stream is starting.",
"dd_optional_adjustments": "Optional adjustments",
"dd_advanced_remapping_title": "Advanced: Mode remapping",
"dd_display_overrides": "Display overrides",
@@ -282,31 +282,31 @@
"dd_resolution_option_disabled": "Do not change resolution",
"dd_resolution_option_manual": "Use manually entered resolution",
"dd_wa_virtual_double_refresh": "Double refresh rate for virtual displays",
- "dd_wa_virtual_double_refresh_desc": "Creates Vibepollo virtual displays at 2x the target refresh to prevent unexplained FPS drops. Leave this on unless a specific game or monitor behaves incorrectly. Note: Manual refresh rate overrides this (no doubling).",
- "dd_wa_hdr_toggle_delay_desc_1": "When using virtual display device (VDD) for streaming, it might incorrectly display HDR color. Vibepollo can try to mitigate this issue, by turning HDR off and then on again.",
- "dd_wa_hdr_toggle_delay_desc_2": "If the value is set to 0, the workaround is disabled (default). If the value is between 0 and 3000 milliseconds, Vibepollo will turn off HDR, wait for the specified amount of time and then turn HDR on again. The recommended delay time is around 500 milliseconds in most cases.",
+ "dd_wa_virtual_double_refresh_desc": "Creates Nimbus virtual displays at 2x the target refresh to prevent unexplained FPS drops. Leave this on unless a specific game or monitor behaves incorrectly. Note: Manual refresh rate overrides this (no doubling).",
+ "dd_wa_hdr_toggle_delay_desc_1": "When using virtual display device (VDD) for streaming, it might incorrectly display HDR color. Nimbus can try to mitigate this issue, by turning HDR off and then on again.",
+ "dd_wa_hdr_toggle_delay_desc_2": "If the value is set to 0, the workaround is disabled (default). If the value is between 0 and 3000 milliseconds, Nimbus will turn off HDR, wait for the specified amount of time and then turn HDR on again. The recommended delay time is around 500 milliseconds in most cases.",
"dd_wa_hdr_toggle_delay_desc_3": "DO NOT use this workaround unless you actually have issues with HDR as it directly impacts stream start time!",
"dd_wa_hdr_toggle_delay": "High-contrast workaround for HDR",
"dd_wa_hdr_toggle": "High-contrast workaround for HDR",
- "dd_wa_hdr_toggle_desc": "When using a virtual display device (VDD), HDR colors can be wrong. Vibepollo can toggle HDR off and back on to mitigate this. Enable only if you see HDR color issues.",
+ "dd_wa_hdr_toggle_desc": "When using a virtual display device (VDD), HDR colors can be wrong. Nimbus can toggle HDR off and back on to mitigate this. Enable only if you see HDR color issues.",
"ds4_back_as_touchpad_click": "Map Back/Select to Touchpad Click",
"ds4_back_as_touchpad_click_desc": "When forcing DS4 emulation, map Back/Select to Touchpad Click",
"ds5_inputtino_randomize_mac": "Randomize virtual controller MAC",
"ds5_inputtino_randomize_mac_desc": "Upon controller registration use a random MAC instead of one based on the controllers internal index to avoid mixing configuration settings of different controllers when the are swapped on client-side.",
"encoder": "Force a Specific Encoder",
- "encoder_desc": "Force a specific encoder, otherwise Vibepollo will select the best available option. Note: If you specify a hardware encoder on Windows, it must match the GPU where the display is connected.",
+ "encoder_desc": "Force a specific encoder, otherwise Nimbus will select the best available option. Note: If you specify a hardware encoder on Windows, it must match the GPU where the display is connected.",
"encoder_software": "Software",
"external_ip": "External IP",
- "external_ip_desc": "If no external IP address is given, Vibepollo will automatically detect external IP",
+ "external_ip_desc": "If no external IP address is given, Nimbus will automatically detect external IP",
"fec_percentage": "FEC Percentage",
"fec_percentage_desc": "Percentage of error correcting packets per data packet in each video frame. Higher values can correct for more network packet loss, but at the cost of increasing bandwidth usage.",
"frame_limiter_fps_limit": "Frame limiter FPS limit",
"frame_limiter_fps_limit_desc": "Optional global FPS limit for the frame limiter. Set to 0 to use the stream's requested FPS.",
"ffmpeg_auto": "auto -- let ffmpeg decide (default)",
"file_apps": "Apps File",
- "file_apps_desc": "The file where current apps of Vibepollo are stored.",
+ "file_apps_desc": "The file where current apps of Nimbus are stored.",
"file_state": "State File",
- "file_state_desc": "The file where current state of Vibepollo is stored",
+ "file_state_desc": "The file where current state of Nimbus is stored",
"gamepad": "Emulated Gamepad Type",
"gamepad_auto": "Automatic selection options",
"gamepad_desc": "Choose which type of gamepad to emulate on the host",
@@ -321,13 +321,13 @@
"global_prep_cmd": "Command Preparations",
"global_prep_cmd_desc": "Configure a list of commands to be executed before or after running any application. If any of the specified preparation commands fail, the application launch process will be aborted.",
"hevc_mode": "HEVC Support",
- "hevc_mode_0": "Vibepollo will advertise support for HEVC based on encoder capabilities (recommended)",
- "hevc_mode_1": "Vibepollo will not advertise support for HEVC",
- "hevc_mode_2": "Vibepollo will advertise support for HEVC Main profile",
- "hevc_mode_3": "Vibepollo will advertise support for HEVC Main and Main10 (HDR) profiles",
+ "hevc_mode_0": "Nimbus will advertise support for HEVC based on encoder capabilities (recommended)",
+ "hevc_mode_1": "Nimbus will not advertise support for HEVC",
+ "hevc_mode_2": "Nimbus will advertise support for HEVC Main profile",
+ "hevc_mode_3": "Nimbus will advertise support for HEVC Main and Main10 (HDR) profiles",
"hevc_mode_desc": "Allows the client to request HEVC Main or HEVC Main10 video streams. HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.",
"high_resolution_scrolling": "High Resolution Scrolling Support",
- "high_resolution_scrolling_desc": "When enabled, Vibepollo will pass through high resolution scroll events from Moonlight clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
+ "high_resolution_scrolling_desc": "When enabled, Nimbus will pass through high resolution scroll events from Moonlight clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
"install_steam_audio_drivers": "Install Steam Audio Drivers",
"install_steam_audio_drivers_desc": "If Steam is installed, this will automatically install the Steam Streaming Speakers driver to support 5.1/7.1 surround sound and muting host audio.",
"key_repeat_delay": "Key Repeat Delay",
@@ -335,7 +335,7 @@
"key_repeat_frequency": "Key Repeat Frequency",
"key_repeat_frequency_desc": "How often keys repeat every second. This configurable option supports decimals.",
"key_rightalt_to_key_win": "Map Right Alt key to Windows key",
- "key_rightalt_to_key_win_desc": "It may be possible that you cannot send the Windows Key from Moonlight directly. In those cases it may be useful to make Vibepollo think the Right Alt key is the Windows key",
+ "key_rightalt_to_key_win_desc": "It may be possible that you cannot send the Windows Key from Moonlight directly. In those cases it may be useful to make Nimbus think the Right Alt key is the Windows key",
"keybindings": "Keybindings",
"keyboard": "Enable Keyboard Input",
"keyboard_desc": "Allows guests to control the host system with the keyboard",
@@ -344,11 +344,11 @@
"lan_encryption_mode_2": "Required for all clients",
"lan_encryption_mode_desc": "This determines when encryption will be used when streaming over your local network. Encryption can reduce streaming performance, particularly on less powerful hosts and clients.",
"locale": "Locale",
- "locale_desc": "The locale used for Vibepollo's user interface.",
+ "locale_desc": "The locale used for Nimbus's user interface.",
"log_path": "Logfile Path",
- "log_path_desc": "The file where the current logs of Vibepollo are stored.",
+ "log_path_desc": "The file where the current logs of Nimbus are stored.",
"max_bitrate": "Maximum Bitrate",
- "max_bitrate_desc": "The maximum bitrate (in Kbps) that Vibepollo will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.",
+ "max_bitrate_desc": "The maximum bitrate (in Kbps) that Nimbus will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.",
"minimum_fps_target": "Minimum FPS Target",
"minimum_fps_target_desc": "The lowest effective FPS a stream can reach. A value of 0 is treated as roughly half of the stream's FPS. A setting of 20 is recommended if you stream 24 or 30fps content.",
"session_token_ttl_seconds": "Web UI Session Timeout (seconds)",
@@ -378,15 +378,15 @@
"mouse": "Enable Mouse Input",
"mouse_desc": "Allows guests to control the host system with the mouse",
"native_pen_touch": "Native Pen/Touch Support",
- "native_pen_touch_desc": "When enabled, Vibepollo will pass through native pen/touch events from Moonlight clients. This can be useful to disable for older applications without native pen/touch support.",
+ "native_pen_touch_desc": "When enabled, Nimbus will pass through native pen/touch events from Moonlight clients. This can be useful to disable for older applications without native pen/touch support.",
"notify_pre_releases": "PreRelease Notifications",
- "notify_pre_releases_desc": "Whether to be notified of new pre-release versions of Vibepollo",
+ "notify_pre_releases_desc": "Whether to be notified of new pre-release versions of Nimbus",
"nvenc_h264_cavlc": "Prefer CAVLC over CABAC in H.264",
"nvenc_h264_cavlc_desc": "Simpler form of entropy coding. CAVLC needs around 10% more bitrate for same quality. Only relevant for really old decoding devices.",
"nvenc_latency_over_power": "Prefer lower encoding latency over power savings",
- "nvenc_latency_over_power_desc": "Vibepollo requests maximum GPU clock speed while streaming to reduce encoding latency. Disabling it is not recommended since this can lead to significantly increased encoding latency.",
+ "nvenc_latency_over_power_desc": "Nimbus requests maximum GPU clock speed while streaming to reduce encoding latency. Disabling it is not recommended since this can lead to significantly increased encoding latency.",
"nvenc_opengl_vulkan_on_dxgi": "Present OpenGL/Vulkan on top of DXGI",
- "nvenc_opengl_vulkan_on_dxgi_desc": "Vibepollo can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted on sunshine program exit.",
+ "nvenc_opengl_vulkan_on_dxgi_desc": "Nimbus can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted on sunshine program exit.",
"nvenc_preset": "Performance preset",
"nvenc_preset_1": "(fastest, default)",
"nvenc_preset_4": "(balanced quality)",
@@ -412,8 +412,8 @@
"origin_web_ui_allowed_pc": "Only localhost may access Web UI",
"origin_web_ui_allowed_wan": "Anyone may access Web UI",
"output_name": "Display Id",
- "output_name_desc_unix": "During Vibepollo startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
- "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Vibepollo startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab.",
+ "output_name_desc_unix": "During Nimbus startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
+ "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Nimbus startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab.",
"ping_timeout": "Ping Timeout",
"ping_timeout_desc": "How long to wait in milliseconds for data from moonlight before shutting down the stream",
"video_max_batch_size_kb": "Max Video Batch Size",
@@ -421,9 +421,9 @@
"pkey": "Private Key",
"pkey_desc": "The private key used for the web UI and Moonlight client pairing. For best compatibility, this should be an RSA-2048 private key.",
"port": "Port",
- "port_alert_1": "Vibepollo cannot use ports below 1024!",
+ "port_alert_1": "Nimbus cannot use ports below 1024!",
"port_alert_2": "Ports above 65535 are not available!",
- "port_desc": "Set the family of ports used by Vibepollo",
+ "port_desc": "Set the family of ports used by Nimbus",
"port_http_port_note": "Use this port to connect with Moonlight.",
"port_note": "Note",
"port_port": "Port",
@@ -445,10 +445,10 @@
"qsv_preset_veryfast": "fastest (lowest quality)",
"qsv_slow_hevc": "Allow Slow HEVC Encoding",
"qsv_slow_hevc_desc": "This can enable HEVC encoding on older Intel GPUs, at the cost of higher GPU usage and worse performance.",
- "restart_note": "Vibepollo is restarting to apply changes.",
+ "restart_note": "Nimbus is restarting to apply changes.",
"stream_audio": "Stream Audio",
"stream_audio_desc": "Whether to stream audio or not. Disabling this can be useful for streaming headless displays as second monitors.",
- "sunshine_name": "Vibepollo Name",
+ "sunshine_name": "Nimbus Name",
"sunshine_name_desc": "The name displayed by Moonlight. If not specified, the PC's hostname is used",
"sw_preset": "SW Presets",
"sw_preset_desc": "Optimize the trade-off between encoding speed (encoded frames per second) and compression efficiency (quality per bit in the bitstream). Defaults to superfast.",
@@ -497,7 +497,7 @@
"dd_config_ensure_active_warning": "Windows does not display the lock screen on external monitors until you click on them, which can cause black screens when streaming. If this is an issue, use the primary display option instead.",
"dd_config_label": "Device configuration",
"dd_snapshot_restore_hotkey": "Restore snapshot hotkey",
- "dd_snapshot_restore_hotkey_desc": "Windows-only global hotkey. Useful for forcing virtual displays off and restoring snapshots when Vibepollo is paused or stuck. Click the field and press the combo you want.",
+ "dd_snapshot_restore_hotkey_desc": "Windows-only global hotkey. Useful for forcing virtual displays off and restoring snapshots when Nimbus is paused or stuck. Click the field and press the combo you want.",
"dd_snapshot_restore_hotkey_capture": "Listening... press a combo now.",
"dd_snapshot_restore_hotkey_reset": "Clear hotkey",
"dd_snapshot_restore_hotkey_invalid": "Unsupported key. Use F1-F24, letters, or digits.",
@@ -507,15 +507,15 @@
"virtual_display_mode_per_client": "Virtual Display (Per Client)",
"virtual_display_mode_shared": "Shared Virtual Display",
"virtual_display_mode_label": "Virtual display mode",
- "virtual_display_mode_step_hint": "Select which display Vibepollo should prepare: keep your physical monitor, create a per-client virtual display, or reuse a shared virtual screen.",
+ "virtual_display_mode_step_hint": "Select which display Nimbus should prepare: keep your physical monitor, create a per-client virtual display, or reuse a shared virtual screen.",
"virtual_display_hdr_tip": "HDR Tip: Run Windows HDR Calibration while streaming and save the profile. Then open the Clients tab and click HDR Color Profile for the client to choose the saved profile.",
"virtual_display_layout_label": "Virtual Display Layout",
- "virtual_display_layout_hint": "Choose how Vibepollo positions and prioritizes your virtual display when it is enabled.",
+ "virtual_display_layout_hint": "Choose how Nimbus positions and prioritizes your virtual display when it is enabled.",
"virtual_display_toggle_label": "Configure Physical or Virtual Display",
- "virtual_display_toggle_hint": "Override the display Vibepollo uses for this app: switch to the Vibepollo virtual display or pick a specific physical monitor. Leave unchecked to follow the global/client choice.",
- "client_display_override_hint": "Override how Vibepollo chooses a display for this client. Leave unchecked to follow the global display settings.",
+ "virtual_display_toggle_hint": "Override the display Nimbus uses for this app: switch to the Nimbus virtual display or pick a specific physical monitor. Leave unchecked to follow the global/client choice.",
+ "client_display_override_hint": "Override how Nimbus chooses a display for this client. Leave unchecked to follow the global display settings.",
"virtual_display_layout_exclusive": "Exclusive",
- "virtual_display_layout_exclusive_desc": "Disable every other monitor so only the Vibepollo virtual display stays visible.",
+ "virtual_display_layout_exclusive_desc": "Disable every other monitor so only the Nimbus virtual display stays visible.",
"virtual_display_layout_extended": "Extended",
"virtual_display_layout_extended_desc": "Keep your physical monitors active and simply add the virtual display as another screen.",
"virtual_display_layout_extended_primary": "Extended + Primary",
@@ -524,8 +524,8 @@
"virtual_display_layout_extended_isolated_desc": "Extend the desktop but park the virtual display far away so the mouse never wanders into it.",
"virtual_display_layout_extended_primary_isolated": "Extended + Primary (Isolated)",
"virtual_display_layout_extended_primary_isolated_desc": "Combine primary + isolation: make the virtual display primary while keeping it out of reach of physical monitors.",
- "virtual_display_status_label": "Vibepollo virtual display driver:",
- "virtual_display_status_hint": "Use Vibepollo's virtual display to spin up a high-refresh virtual monitor automatically. If the driver reports an error, reinstall Vibepollo or repair the driver before streaming.",
+ "virtual_display_status_label": "Nimbus virtual display driver:",
+ "virtual_display_status_hint": "Use Nimbus's virtual display to spin up a high-refresh virtual monitor automatically. If the driver reports an error, reinstall Nimbus or repair the driver before streaming.",
"sudovda_status_unknown": "Unknown",
"sudovda_status_ready": "Ready",
"sudovda_status_uninitialized": "Not initialized",
@@ -544,13 +544,13 @@
"crash_dump_dismiss_success": "Crash notification dismissed.",
"crash_dump_dismiss_error": "Failed to dismiss crash notification.",
"update_check_interval": "Update Check Interval (seconds)",
- "update_check_interval_desc": "How often Vibepollo should check for updates automatically (based on git tags). Set 0 to disable periodic checks.",
+ "update_check_interval_desc": "How often Nimbus should check for updates automatically (based on git tags). Set 0 to disable periodic checks.",
"hot_applied_now": "Settings saved and applied immediately.",
"hot_deferred": "Settings saved. Changes will apply when the current stream ends (or on next start).",
"saving": "Saving…",
"saved_success": "Saved successfully",
"saved_deferred": "Changes will apply on next stream",
- "restart_required": "Restart Vibepollo to apply changes",
+ "restart_required": "Restart Nimbus to apply changes",
"manual_save_needed": "Manual save required (restart changes)",
"waiting_for_changes": "Waiting for changes…",
"dd_hdr_request_override": "HDR request override",
@@ -561,7 +561,7 @@
"lossless_scaling_path": "Lossless Scaling executable",
"rtss_frame_limit_type": "RTSS frame limit type",
"rtss_install_path": "RTSS install path",
- "vibeshine_file_state": "Vibepollo state file",
+ "vibeshine_file_state": "Nimbus state file",
"virtual_display_layout": "Virtual display layout",
"virtual_display_mode": "Virtual display mode",
"adapter_name_placeholder_unix": "/dev/dri/renderD128",
@@ -585,7 +585,7 @@
"hide_tray_controls": "Hide tray control options",
"hide_tray_controls_desc": "Do not show \"Force Stop\", \"Restart\" and \"Quit\" in tray menu.",
"fallback_mode": "Fallback Display Mode",
- "fallback_mode_desc": "Vibepollo will use this mode when the client does not provide a mode or when the app is launched through the web UI. Format: [Width]x[Height]x[FPS]",
+ "fallback_mode_desc": "Nimbus will use this mode when the client does not provide a mode or when the app is launched through the web UI. Format: [Width]x[Height]x[FPS]",
"keep_sink_default": "Keep virtual sink as default",
"keep_sink_default_desc": "Leave the virtual audio sink selected as the default playback device while streaming audio is active.",
"auto_capture_sink": "Auto capture current sink",
@@ -649,7 +649,7 @@
"send": "Send",
"warning_msg": "Make sure you have access to the client you are pairing with. This software can give total control to your computer, so be careful!",
"display_mode_override": "Display mode override",
- "display_mode_override_desc": "Force Vibepollo to use this resolution and refresh rate for this client (format: 1920x1080x60). Leave blank to use the client's request."
+ "display_mode_override_desc": "Force Nimbus to use this resolution and refresh rate for this client (format: 1920x1080x60). Leave blank to use the client's request."
},
"permissions": {
"group_action": "Action",
@@ -682,7 +682,7 @@
},
"troubleshooting": {
"dd_reset": "Reset Persistent Display Device Settings",
- "dd_reset_desc": "If Vibepollo is stuck trying to restore the changed display device settings, you can reset the settings and proceed to restore the display state manually.",
+ "dd_reset_desc": "If Nimbus is stuck trying to restore the changed display device settings, you can reset the settings and proceed to restore the display state manually.",
"dd_reset_error": "Error while resetting persistence!",
"dd_reset_success": "Success resetting persistence!",
"dd_export_golden": "Export Golden Display Restore",
@@ -690,7 +690,7 @@
"dd_export_golden_success": "Exported golden display snapshot.",
"dd_export_golden_error": "Failed to export golden display snapshot.",
"dd_golden_title": "Golden Display Restore",
- "dd_golden_help": "Save a snapshot of your current Windows display layout (which screens are on, primary display, resolution, HDR). Vibepollo uses this if your monitor settings don’t stick — for example after a reboot or at the sign‑in screen. This reduces the chance of coming back to a PC with the primary display still turned off.",
+ "dd_golden_help": "Save a snapshot of your current Windows display layout (which screens are on, primary display, resolution, HDR). Nimbus uses this if your monitor settings don’t stick — for example after a reboot or at the sign‑in screen. This reduces the chance of coming back to a PC with the primary display still turned off.",
"dd_golden_status_present": "Snapshot present",
"dd_golden_status_missing": "No snapshot found",
"dd_golden_create": "Create Snapshot",
@@ -704,7 +704,7 @@
"force_close_error": "Error while closing Application",
"force_close_success": "Application Closed Successfully!",
"logs": "Logs",
- "logs_desc": "See the logs uploaded by Vibepollo",
+ "logs_desc": "See the logs uploaded by Nimbus",
"logs_find": "Find...",
"search_matches": "{count} matches",
"search_no_matches": "No matches",
@@ -716,9 +716,9 @@
"search_context": "{count} lines of context",
"search_line": "Line",
"jump_to_latest": "Jump to latest logs",
- "restart_sunshine": "Restart Vibepollo",
- "restart_sunshine_desc": "If Vibepollo isn't working properly, you can try restarting it. This will terminate any running sessions.",
- "restart_sunshine_success": "Vibepollo is restarting",
+ "restart_sunshine": "Restart Nimbus",
+ "restart_sunshine_desc": "If Nimbus isn't working properly, you can try restarting it. This will terminate any running sessions.",
+ "restart_sunshine_success": "Nimbus is restarting",
"troubleshooting": "Troubleshooting",
"unpair_all": "Unpair All",
"unpair_all_error": "Error while unpairing",
@@ -733,9 +733,9 @@
"new_logs_available": "New logs available — jump to latest",
"copy_logs": "Copy Logs",
"collect_playnite_logs": "Export Logs",
- "collect_playnite_logs_desc": "Export Vibepollo log, Playnite/plugin logs, and display-helper logs.",
+ "collect_playnite_logs_desc": "Export Nimbus log, Playnite/plugin logs, and display-helper logs.",
"export_crash_bundle": "Export Crash Bundle",
- "export_crash_bundle_desc": "Download logs along with the most recent Vibepollo crash dump."
+ "export_crash_bundle_desc": "Download logs along with the most recent Nimbus crash dump."
},
"welcome": {
"confirm_password": "Confirm password",
@@ -747,9 +747,9 @@
},
"rtss": {
"tab": "Frame Limiter",
- "desc": "Vibepollo can apply a global frame limit via RTSS (recommended) or NVIDIA Control Panel (experimental), then restores the original driver settings when streaming stops.",
+ "desc": "Nimbus can apply a global frame limit via RTSS (recommended) or NVIDIA Control Panel (experimental), then restores the original driver settings when streaming stops.",
"frame_limiter_disable_vsync": "Force VSYNC off while streaming",
- "frame_limiter_disable_vsync_desc": "When enabled, Vibepollo sets the NVIDIA driver VSYNC setting to Off for the duration of the stream and restores the previous value afterward. If NVIDIA overrides are unavailable, Vibepollo forces the display to run at its highest refresh rate as a best-effort fallback.",
+ "frame_limiter_disable_vsync_desc": "When enabled, Nimbus sets the NVIDIA driver VSYNC setting to Off for the duration of the stream and restores the previous value afterward. If NVIDIA overrides are unavailable, Nimbus forces the display to run at its highest refresh rate as a best-effort fallback.",
"frame_limiter_fps_limit": "Frame limiter FPS limit",
"frame_limiter_fps_limit_desc": "Optional global FPS limit for the frame limiter. Set to 0 to use the stream's requested FPS.",
"provider_label": "Frame limiter provider",
@@ -779,9 +779,9 @@
"install_path_placeholder": "C:\\Program Files (x86)\\RivaTuner Statistics Server",
"install_path_desc": "Root install folder (leave blank to auto-detect under Program Files / Program Files (x86)).",
"enable_frame_limiter": "Enable frame limiter",
- "enable_frame_limiter_desc": "When enabled, Vibepollo applies a global frame limit using your chosen provider for the duration of each stream, then restores the previous driver setting afterward.",
+ "enable_frame_limiter_desc": "When enabled, Nimbus applies a global frame limit using your chosen provider for the duration of each stream, then restores the previous driver setting afterward.",
"sync_limiter_mode": "SyncLimiter mode",
- "sync_limiter_desc": "Advanced users only. Vibepollo mirrors this into RTSS. See the comparison below before changing it.",
+ "sync_limiter_desc": "Advanced users only. Nimbus mirrors this into RTSS. See the comparison below before changing it.",
"sync_limiter_do_not_change": "Do not change",
"sync_limiter_async": "Async",
"sync_limiter_front_edge": "Front edge sync",
@@ -807,13 +807,13 @@
"sync_limiter_back_use": "Displays that behave better with vsync-style pacing",
"sync_limiter_reflex_short": "NVIDIA Reflex",
"sync_limiter_reflex_latency": "Variable; depends on driver",
- "sync_limiter_reflex_stutter": "Can conflict with Vibepollo (microstutter likely)",
+ "sync_limiter_reflex_stutter": "Can conflict with Nimbus (microstutter likely)",
"sync_limiter_reflex_use": "Only for testing when Reflex is mandatory",
"recommend_title": "RTSS recommended",
"recommend_copy": "RTSS delivers the smoothest streaming experience. Install it if missing; NVIDIA's frame limiter is not recommended because it cannot guarantee perfect frame pacing.",
- "status_bootstrap": "RTSS detected; Vibepollo will refresh RTSS configuration on the next stream",
- "status_bootstrap_hint": "Vibepollo manages RTSS configuration automatically; no action needed.",
- "status_autolaunch_hint": "Vibepollo will launch RTSS automatically when streaming starts.",
+ "status_bootstrap": "RTSS detected; Nimbus will refresh RTSS configuration on the next stream",
+ "status_bootstrap_hint": "Nimbus manages RTSS configuration automatically; no action needed.",
+ "status_autolaunch_hint": "Nimbus will launch RTSS automatically when streaming starts.",
"sync_limiter_help_advantages": "Advantages",
"sync_limiter_help_disadvantages": "Disadvantages",
"sync_limiter_async_advantages": "Stable timing regardless of refresh alignment; very smooth at odd FPS or Hz combos",
@@ -828,7 +828,7 @@
"frameLimiter": {
"stepTitle": "Frame pacing and limiter",
"enable": "Enable frame limiter",
- "enableHint": "Vibepollo applies the selected limiter provider at stream start and restores the previous driver setting when the stream ends.",
+ "enableHint": "Nimbus applies the selected limiter provider at stream start and restores the previous driver setting when the stream ends.",
"providerLabel": "Limiter provider",
"providerHint": "Auto prefers RTSS whenever it is available and falls back to the NVIDIA Control Panel limiter if needed. NVIDIA's limiter is not recommended because it cannot guarantee perfect frame pacing.",
"limitLabel": "FPS limit override",
@@ -849,13 +849,13 @@
},
"vsyncUllmLabel": "Disable VSYNC while streaming",
"vsyncUllmForcedByDummyPlug": "Forced on because the dummy plug HDR workaround requires VSYNC to be off for 10-bit output.",
- "vsyncUllmHintNv": "Vibepollo will force the NVIDIA driver VSYNC setting to Off during the stream and restore it afterward. Use this if you globally enable VSYNC but want Vibepollo sessions without it.",
- "vsyncUllmHintGeneric": "Vibepollo will run the display at its highest available refresh rate during the stream as a best-effort VSYNC workaround. NVIDIA overrides are not available on this system.",
+ "vsyncUllmHintNv": "Nimbus will force the NVIDIA driver VSYNC setting to Off during the stream and restore it afterward. Use this if you globally enable VSYNC but want Nimbus sessions without it.",
+ "vsyncUllmHintGeneric": "Nimbus will run the display at its highest available refresh rate during the stream as a best-effort VSYNC workaround. NVIDIA overrides are not available on this system.",
"rtssPath": "RTSS install path",
"rtssPathPlaceholder": "C:\\Program Files (x86)\\RivaTuner Statistics Server",
"rtssPathHint": "Root install folder (leave blank to auto-detect under Program Files / Program Files (x86)).",
"syncLimiterLabel": "RTSS SyncLimiter mode",
- "syncLimiterHint": "Optional: adjust RTSS SyncLimiter when Vibepollo uses RTSS to limit framerate.",
+ "syncLimiterHint": "Optional: adjust RTSS SyncLimiter when Nimbus uses RTSS to limit framerate.",
"rtssMissing": "RTSS was not detected. Install RTSS or adjust the install path to use it as a limiter.",
"status": {
"unknown": "Frame limiter status unavailable.",
@@ -871,24 +871,24 @@
"rtssDetected": "RTSS detected and ready.",
"rtssNotDetected": "RTSS not detected.",
"none": "None",
- "rtssBootstrap": "RTSS detected; Vibepollo will refresh RTSS configuration when streaming starts.",
- "rtssBootstrapHint": "Vibepollo manages RTSS configuration automatically; no action needed.",
- "rtssAutolaunchHint": "Vibepollo will launch RTSS automatically when a stream begins."
+ "rtssBootstrap": "RTSS detected; Nimbus will refresh RTSS configuration when streaming starts.",
+ "rtssBootstrapHint": "Nimbus manages RTSS configuration automatically; no action needed.",
+ "rtssAutolaunchHint": "Nimbus will launch RTSS automatically when a stream begins."
},
"actions": {
"refresh": "Refresh"
},
"noticeTitle": "RTSS recommended",
- "noticeCopy": "RTSS offers the most stable frame pacing. Vibepollo will use it automatically when available; NVIDIA's limiter is not recommended because it cannot guarantee perfect frame pacing."
+ "noticeCopy": "RTSS offers the most stable frame pacing. Nimbus will use it automatically when available; NVIDIA's limiter is not recommended because it cannot guarantee perfect frame pacing."
},
"offline": {
- "title": "Lost Connection to Vibepollo",
- "description": "The web interface lost connectivity to the Vibepollo service.",
+ "title": "Lost Connection to Nimbus",
+ "description": "The web interface lost connectivity to the Nimbus service.",
"retrying": "Attempting to reconnect… The page will refresh once available.",
"refresh_now": "Refresh now",
- "close_hint": "If you stopped Vibepollo intentionally, you may close this tab.",
- "output_name_desc_unix": "During Vibepollo startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
- "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Vibepollo startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab."
+ "close_hint": "If you stopped Nimbus intentionally, you may close this tab.",
+ "output_name_desc_unix": "During Nimbus startup, you should see the list of detected displays. Note: You need to use the id value inside the parenthesis. Below is an example; the actual output can be found in the Troubleshooting tab.",
+ "output_name_desc_windows": "Manually specify a display device id to use for capture. If unset, the primary display is captured. Note: If you specified a GPU above, this display must be connected to that GPU. During Nimbus startup, you should see the list of detected displays. Below is an example; the actual output can be found in the Troubleshooting tab."
},
"resources": {
"title": "Resources"
@@ -969,14 +969,14 @@
"confirm_remove_title": "Remove Client",
"confirm_remove_message": "Are you sure you want to remove this client? It will need to be re-paired.",
"confirm_remove_title_named": "Remove Client \"{name}\"?",
- "confirm_remove_message_named": "This will unpair {name} from Vibepollo. They will need to pair again to connect.",
+ "confirm_remove_message_named": "This will unpair {name} from Nimbus. They will need to pair again to connect.",
"confirm_unpair_all_title": "Unpair All Clients",
"confirm_unpair_all_message": "Are you sure you want to unpair all clients? They will all need to be re-paired.",
"confirm_unpair_all_message_count": "This will unpair all {count} client(s). They will all need to pair again to connect."
},
"playnite": {
"title": "Playnite Integration",
- "desc": "Vibepollo can sync your Playnite library so your installed games appear automatically. First, install Playnite, run it, and configure it to start with Windows. Then install the Vibepollo plugin below to enable the integration.",
+ "desc": "Nimbus can sync your Playnite library so your installed games appear automatically. First, install Playnite, run it, and configure it to start with Windows. Then install the Nimbus plugin below to enable the integration.",
"only_windows": "Playnite integration is available on Windows only.",
"status_title": "Plugin Status",
"status_overall": "Status",
@@ -986,7 +986,7 @@
"status_connected": "Connected",
"status_disabled": "Disabled",
"status_waiting": "Limited",
- "limited_tooltip": "Games cannot be auto-synced while Playnite is closed. Existing games added to Vibepollo will still work. Once you launch Playnite, syncing resumes automatically.",
+ "limited_tooltip": "Games cannot be auto-synced while Playnite is closed. Existing games added to Nimbus will still work. Once you launch Playnite, syncing resumes automatically.",
"refresh_status": "Refresh Status",
"maintenance_title": "Maintenance",
"copy_path": "Copy",
@@ -999,8 +999,8 @@
"status_not_running_unknown": "Playnite not running — plugin status unknown",
"status_unknown": "Playnite not detected",
"selects_disabled_hint": "Cannot modify without Playnite connectivity. Start Playnite to enable this.",
- "install_button": "Install Vibepollo Plugin",
- "reinstall_button": "Reinstall Vibepollo Plugin",
+ "install_button": "Install Nimbus Plugin",
+ "reinstall_button": "Reinstall Nimbus Plugin",
"upgrade_button": "Upgrade Plugin",
"uninstall_button": "Uninstall Plugin",
"uninstall_success": "Plugin uninstalled successfully.",
@@ -1016,7 +1016,7 @@
"plugin_outdated": "A newer Playnite plugin is available. Installed: v{installed}, Latest: v{latest}.",
"auto_sync": "Synchronize recently played games automatically",
"sync_all_installed": "Synchronize every installed Playnite game",
- "sync_all_installed_desc": "Adds every installed Playnite game to Vibepollo, alongside recent and category selections.",
+ "sync_all_installed_desc": "Adds every installed Playnite game to Nimbus, alongside recent and category selections.",
"enable_autosync_hint": "Enable synchronization to edit these settings.",
"recent_games": "Recent games to sync",
"recent_games_desc": "Maximum number of recent games to auto-sync. 0 = disable recent syncing.",
@@ -1027,7 +1027,7 @@
"cleanup_policy": "Cleanup Policy",
"policy_keep_until_replaced": "Keep until replaced (default)",
"policy_prune_immediately": "Always prune games that no longer qualify (may leave empty slots)",
- "policy_explainer": "Choose how Vibepollo removes old auto-synced games.",
+ "policy_explainer": "Choose how Nimbus removes old auto-synced games.",
"sync_categories": "Categories to sync",
"sync_categories_help": "Pick Playnite categories sync, which will add all games in that category regardless if they are recently played or not. This will not consume any recently played slot counts, it is simply appended to them.",
"sync_plugins": "Include library plugins",
@@ -1040,7 +1040,7 @@
"plugins_placeholder": "Pick library plugins to exclude",
"plugins_include_placeholder": "Include games from these plugins",
"remove_uninstalled": "Remove uninstalled games automatically",
- "remove_uninstalled_desc": "When enabled, Vibepollo removes auto-synced games as soon as they are uninstalled in Playnite.",
+ "remove_uninstalled_desc": "When enabled, Nimbus removes auto-synced games as soon as they are uninstalled in Playnite.",
"extensions_dir": "Extensions directory",
"install_dir": "Installation path override",
"save_success": "Settings saved.",
@@ -1086,7 +1086,7 @@
"summary_activity_ignored": "Activity window is ignored.",
"summary_keep_until_replaced": "Games stay until a newer game replaces them.",
"summary_prune_immediately": "Games are pruned when they no longer qualify.",
- "summary_all_installed": "All installed Playnite games are kept in Vibepollo.",
+ "summary_all_installed": "All installed Playnite games are kept in Nimbus.",
"summary_plugin_include": "Includes all games from {count} selected library plugins.",
"summary_remove_uninstalled_on": "Uninstalled games are removed automatically.",
"summary_remove_uninstalled_off": "Uninstalled games remain until you remove them manually.",
@@ -1162,7 +1162,7 @@
"logout_refresh_hint": "You may now close this tab or refresh the page to sign back in.",
"logout_refresh_button": "Refresh to Sign In",
"sessions_heading": "Trusted Devices",
- "sessions_description": "Devices with active Vibepollo sessions. Remove entries to sign them out remotely.",
+ "sessions_description": "Devices with active Nimbus sessions. Remove entries to sign them out remotely.",
"sessions_device": "Device",
"sessions_activity": "Activity",
"sessions_status": "Status",
From 5bdc078403fc5bd170a55cd499fcf51a2d6db845 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 17:30:18 +1000
Subject: [PATCH 08/60] feat: apply Nimbus web identity tokens
---
docs/ui-identity-plan.md | 12 ++-
src_assets/common/assets/web/App.vue | 24 +++---
src_assets/common/assets/web/Login.vue | 5 +-
src_assets/common/assets/web/naive-theme.ts | 10 +--
.../common/assets/web/styles/tailwind.css | 30 +++++++
.../common/assets/web/tailwind.config.js | 79 ++++++++-----------
6 files changed, 93 insertions(+), 67 deletions(-)
diff --git a/docs/ui-identity-plan.md b/docs/ui-identity-plan.md
index 00aaec2560..88886ab62d 100644
--- a/docs/ui-identity-plan.md
+++ b/docs/ui-identity-plan.md
@@ -66,11 +66,21 @@ flowchart LR
| Slice | Scope | Validation |
| --- | --- | --- |
-| UI-1 | Browser title, login shell, dashboard greeting, resource links | Vite build and VM screenshot |
+| UI-1 | Browser title, login shell, dashboard greeting, resource links, app-shell token pass | Vite build and VM screenshot |
| UI-2 | Dashboard status cards and update/release alert layout | Vite build and responsive screenshots |
| UI-3 | Settings navigation and form density pass | Vite build, keyboard navigation, mobile width check |
| UI-4 | Changelog and support surfaces | Vite build, no upstream release links |
+## Implementation Notes
+
+- The first implementation slice should replace inherited Apollo/Sunshine visual
+ anchors before larger layout work: shell navigation, login/logout brand mark,
+ and semantic Tailwind/Naive UI color tokens.
+- Keep source compatibility names separate from visible product identity. If a
+ backend feature still uses an inherited folder, profile, or executable name,
+ prefer neutral wording such as "managed profile" until that runtime migration
+ is complete.
+
## Figma Status
A private `Nimbus UI Kit v0.1` Figma file exists for maintainer exploration.
diff --git a/src_assets/common/assets/web/App.vue b/src_assets/common/assets/web/App.vue
index 99b80c6771..d717b984f2 100644
--- a/src_assets/common/assets/web/App.vue
+++ b/src_assets/common/assets/web/App.vue
@@ -4,12 +4,10 @@
-
success: false,
loading: false,
passwordData: {
- newUsername: 'apollo',
+ newUsername: 'nimbus',
newPassword: '',
confirmNewPassword: '',
},
From 1ff4cfbc4ef91b8a1c006b948aec5f11202cf31e Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 17:40:28 +1000
Subject: [PATCH 12/60] docs: include static onboarding validation
---
docs/release-build-audit.md | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index 134b4dd78f..9495251f2e 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -217,10 +217,11 @@ candidate.
Validation date: 2026-05-21
-Validated commits: `2ab4bf99`, `5bdc0784`, `3d8197ae`
+Validated commits: `2ab4bf99`, `5bdc0784`, `3d8197ae`, `79de18b6`
Scope: revalidate the additional Nimbus visible web copy sweep, first app-shell
-identity token pass, and Windows status/log message rebrand.
+identity token pass, Windows status/log message rebrand, and static
+onboarding/header branding pass.
Result:
@@ -228,6 +229,7 @@ Result:
| --- | --- | --- |
| Web UI production build | Pass | `npm run build` passes. Vite still reports inherited large vendor chunk warnings. |
| Targeted visible-name scan | Pass | Targeted Vue shell, app-edit, troubleshooting, Playnite, and English locale surfaces no longer contain `Vibepollo`. |
+| Static onboarding scan | Pass | `welcome.html`, `login.html`, and `template_header.html` no longer reference the Apollo logo, `sunshine.ico`, or the `apollo` default first username. |
| English locale JSON parse | Pass | `en.json`, `en_GB.json`, and `en_US.json` parse successfully after the broader Nimbus copy sweep. |
| Native Windows host build | Pass | `cmake --build build\nimbus-package-validation --target sunshine --config Release -j 6` passes when `C:\msys64\ucrt64\bin` is on `PATH`. |
| Figma UI kit automation | Blocked | Existing Figma Starter-plan MCP call limit still blocks automated UI kit population. `docs/ui-identity-plan.md` remains the implementation source of truth. |
@@ -236,6 +238,8 @@ Current visual-design state:
- The Vue app shell and login/logout surfaces no longer depend on the inherited
Apollo logo image.
+- Legacy first-run and login HTML use the Nimbus mark and `nimbus` as the
+ default first username.
- Tailwind semantic tokens now use the Nimbus blue, Lucent mint, neutral host
console, amber, green, and red token direction from `docs/ui-identity-plan.md`.
- RTSS and Windows troubleshooting status text now uses Nimbus wording for
From 0b4966f80464e61a42121fa94e55a89043583619 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 17:41:46 +1000
Subject: [PATCH 13/60] docs: refresh first alpha release notes
---
docs/packaging-identity-plan.md | 4 +++-
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 22 +++++++++++++++----
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/docs/packaging-identity-plan.md b/docs/packaging-identity-plan.md
index 35342399e2..5a31894b69 100644
--- a/docs/packaging-identity-plan.md
+++ b/docs/packaging-identity-plan.md
@@ -108,7 +108,7 @@ Do not change these until there is a tested migration plan.
| CPack package name | `Nimbus` | Changed in Phase C. Local package build generated `Nimbus.msi` and `NimbusSetup.exe`. |
| CPack vendor | `Kuno Labs` | Changed in Phase C. |
| CPack contact | `https://github.com/kunolabs/Nimbus/issues` | Changed in Phase C. |
-| Windows install directory | `Apollo` | Defer or migrate with explicit install-path behavior. |
+| Windows install directory | `Nimbus` for fresh installs; inherited Apollo paths are still detected for upgrade/migration compatibility | Changed for fresh install defaults. Validate upgrade and uninstall cleanup before release. |
| WiX upgrade GUID | `{E3FA501A-85F8-4187-85A7-D6E6BDC7EDA1}` | Preserve unless we intentionally break upgrade lineage. |
| WiX product-line seed | `Vibepollo-.` | Treat as high-risk. Change only with upgrade testing. |
| Bootstrapper namespace | `VibepolloInstaller` | Split cosmetic UI naming from installer detection logic. |
@@ -185,6 +185,8 @@ flowchart LR
- Change user-facing package metadata to Nimbus.
- Rename generated release artifacts to Nimbus.
- Update bootstrapper UI strings and support links.
+- Update fresh-install defaults to Nimbus while preserving inherited Apollo and
+ Vibepollo detection paths for compatibility.
- Keep service names, config paths, and upgrade GUIDs unchanged unless the test
plan proves a migration is safe.
- Build on Windows and inspect the installer, generated filenames, Start menu
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index b5bfc68656..c87ccc2a69 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -27,6 +27,11 @@ has wider testers.
- Retargeted the Web UI release checks to `kunolabs/Nimbus` and filtered update
banners to Nimbus-owned `nimbus-v*` tags so the alpha cannot advertise an
inherited Vibepollo download or downgrade path.
+- Rebranded the visible Vue Web UI shell, English UI copy, static first-run
+ onboarding, login header, favicon, and Windows status messages to Nimbus.
+- Added the first Nimbus host-console token pass so the Web UI moves away from
+ inherited Apollo/Sunshine visual identity while keeping compatibility-safe
+ runtime identifiers in place.
## Compatibility Notes
@@ -43,13 +48,22 @@ feedback:
## Verification
-Local package validation has passed for the Phase C packaging slice:
+Historical local package validation passed for the Phase C packaging slice:
- `NimbusSetup.exe` was generated locally.
- `Nimbus.msi` was generated locally.
- Authenticode status was `NotSigned`, as expected for the unsigned alpha path.
- SignPath signing and symbol publishing were skipped.
+Current source validation has passed after the UI and status-message rebrand:
+
+- Web UI production build passes with inherited large vendor chunk warnings.
+- English locale JSON files parse successfully.
+- Native Windows host target builds successfully when MSYS2 UCRT64 is on
+ `PATH`.
+- The current full package target is blocked on this machine until WiX v3
+ `candle.exe` and `light.exe` are available again.
+
Pending before release:
- Fresh install in a Windows VM or snapshot fixture.
@@ -67,9 +81,9 @@ Pending before release:
artifacts.
- Runtime identity migration is not complete; this alpha is branded Nimbus at
the public package layer, not a full rename of every inherited runtime id.
-- The Web UI may still include inherited Vibepollo, Apollo, or Sunshine wording,
- but update banners and release-note links are now restricted to Nimbus
- releases.
+- Some compatibility routes, filenames, service names, icons, docs links, and
+ internal comments may still include inherited Vibepollo, Apollo, or Sunshine
+ wording until each migration surface has a dedicated test plan.
- Symbols, SignPath signing, WebRTC asset publishing, and automatic issue
closure remain disabled.
From b5bba63fec250e776ba3302de398fd0a354a0d69 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 17:50:06 +1000
Subject: [PATCH 14/60] docs: record current Windows package validation
---
docs/building.md | 6 ++
docs/release-build-audit.md | 61 +++++++++++++++----
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 15 ++++-
3 files changed, 69 insertions(+), 13 deletions(-)
diff --git a/docs/building.md b/docs/building.md
index a8b2e5baec..1c8ade0744 100644
--- a/docs/building.md
+++ b/docs/building.md
@@ -120,6 +120,12 @@ The `package_installer` target uses CPack's WiX generator and requires WiX Tools
When building from MSYS2, configure CMake with Windows Git to keep generated version metadata clean:
`-DGIT_EXECUTABLE=C:/Progra~1/Git/cmd/git.exe`.
+CPack WiX performs ICE validation through Windows Installer services. If the
+package build reaches WiX but fails in a sandboxed shell because the Windows
+Installer service cannot be accessed, rerun the same package command from a
+normal PowerShell or approved unsandboxed Codex command. Do not disable ICE
+validation for release-candidate evidence.
+
On Windows, Nimbus prefers the standard Node.js `npm.cmd` launcher for the CMake web UI package step and stores npm
cache data under the CMake build directory. If a build tree was configured before that change, clear the cached npm
path before packaging:
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index 9495251f2e..c924a6fdb9 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -69,10 +69,9 @@ Applied hardening:
- Main release creation no longer closes `fixed` issues directly.
- The separate fixed-issue release closer is disabled.
-Remaining release blocker: package branding now emits Nimbus-named artifacts,
-but the final package must be rebuilt from the current release-prep commit. A
-release tag is still blocked until the current package builds with WiX available,
-installer execution is tested in a VM or snapshot fixture, and release notes are
+Remaining release blocker: the current release-prep commit now builds
+Nimbus-named Windows artifacts locally, but a release tag is still blocked until
+installer execution is tested in a VM or snapshot fixture and release notes are
prepared.
Decision: CI is safer for normal branch work and manual investigation, but do
@@ -202,16 +201,15 @@ cmake -S . -B build\nimbus-package-validation -UNPM
cmake --build build\nimbus-package-validation --target package_installer --config Release -j 6
```
-Current package blocker:
+Historical package blocker:
```text
Could not find the WiX candle executable.
```
-Install WiX Toolset v3.14.1 or make its portable `bin` directory discoverable
-before rerunning the final package build. The old `82fa5cdd` artifacts above are
-historical validation evidence only; do not promote them as the current release
-candidate.
+This blocker was resolved by making WiX Toolset v3.14.1 portable binaries
+discoverable through `WIX`. The old `82fa5cdd` artifacts above are historical
+validation evidence only; do not promote them as the current release candidate.
## Local UI And Status Revalidation
@@ -245,6 +243,46 @@ Current visual-design state:
- RTSS and Windows troubleshooting status text now uses Nimbus wording for
user-visible guidance.
+## Current Full Package Revalidation
+
+Validation date: 2026-05-21
+
+Validated source commit: `0b4966f8`
+
+Scope: rebuild the full Windows package after the visible Nimbus web shell,
+static onboarding, Windows status copy, release-note, and release-safety passes.
+This validates generated package artifacts, not installer execution on a target
+machine.
+
+Command shape:
+
+```powershell
+$env:PATH = 'C:\msys64\ucrt64\bin;' + $env:PATH
+$env:WIX = 'K:\CODEX\game-dev\game-streaming\Nimbus\build\nimbus-package-validation\tools\wix314'
+cmake --build build\nimbus-package-validation --target package_installer --config Release -j 6
+```
+
+Result:
+
+| Check | Result | Notes |
+| --- | --- | --- |
+| Web UI production build | Pass | Vite still reports inherited large vendor chunk warnings only. |
+| CPack WiX MSI | Pass | Initial sandbox run reached WiX but failed ICE validation because Windows Installer service access was unavailable; rerunning outside the sandbox with the same `WIX` path passed. |
+| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.38`, `0b4966f8`, `Kuno Labs`. |
+| Signing | Skipped | `SIGNPATH_API_TOKEN` was unset; output is unsigned. |
+| Installer execution | Pending | Fresh install, uninstall, reinstall, and upgrade behavior still need VM fixture records. |
+
+Artifacts:
+
+| Artifact | Size | SHA256 |
+| --- | ---: | --- |
+| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,360 | `41A5EF596C9C04ACFC792A1A8EB3591CEE970F995A64ABAC80331770C45DA471` |
+| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,741 | `02697C964EA22CA2E7AD840BD355D943ECC59CE64A184F573A12F9B781904F85` |
+
+Current caveat: these artifacts are newer and better branded than the earlier
+`82fa5cdd` validation artifacts, but they are still local validation artifacts
+until VM install and upgrade evidence is recorded.
+
## Required Secrets Before Release CI
| Secret | Purpose | Current Risk |
@@ -264,5 +302,6 @@ Current visual-design state:
## Current Verdict
Nimbus is ready for documentation, issue triage work, and first-alpha release
-planning. It is not yet ready for public release-tag publication because
-installer execution and upgrade behavior still need fixture validation.
+planning. The current Windows package build now completes locally, but Nimbus is
+not yet ready for public release-tag publication because installer execution and
+upgrade behavior still need fixture validation.
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index c87ccc2a69..e967898b9c 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -61,8 +61,19 @@ Current source validation has passed after the UI and status-message rebrand:
- English locale JSON files parse successfully.
- Native Windows host target builds successfully when MSYS2 UCRT64 is on
`PATH`.
-- The current full package target is blocked on this machine until WiX v3
- `candle.exe` and `light.exe` are available again.
+- The current full package target passes when `WIX` points at WiX Toolset v3.14.1
+ portable binaries and the WiX ICE validation step runs outside the Codex
+ sandbox.
+
+Current local package artifacts from commit `0b4966f8`:
+
+| Artifact | Size | SHA256 |
+| --- | ---: | --- |
+| `NimbusSetup.exe` | 25,871,360 | `41A5EF596C9C04ACFC792A1A8EB3591CEE970F995A64ABAC80331770C45DA471` |
+| `Nimbus.msi` | 25,606,741 | `02697C964EA22CA2E7AD840BD355D943ECC59CE64A184F573A12F9B781904F85` |
+
+These are local validation artifacts, not release candidates, until the pending
+VM fixture checks below are recorded.
Pending before release:
From 57d018758f8a9ba278b312d375f2f4528e5a3cc3 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 17:59:24 +1000
Subject: [PATCH 15/60] fix: retarget remaining visible host branding
---
docs/client-controls.md | 49 +++++++++++++++++++
packaging/windows/wix/custom_actions.wxs | 2 +-
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 3 ++
src/config.cpp | 2 +-
src/main.cpp | 6 +--
src/network.cpp | 2 +-
src/platform/common.h | 2 +-
src_assets/common/assets/web/apps.html | 6 +--
.../assets/web/configs/tabs/AudioVideo.vue | 2 +-
src_assets/common/assets/web/pin.html | 6 +--
.../windows/misc/service/install-service.bat | 4 +-
11 files changed, 68 insertions(+), 16 deletions(-)
create mode 100644 docs/client-controls.md
diff --git a/docs/client-controls.md b/docs/client-controls.md
new file mode 100644
index 0000000000..6185f20fa1
--- /dev/null
+++ b/docs/client-controls.md
@@ -0,0 +1,49 @@
+# Client Controls
+
+Nimbus keeps compatibility with Moonlight-compatible clients while exposing a
+few host-side controls for pairing, permissions, display overrides, and client
+commands.
+
+## Permission System
+
+Each paired client can be allowed or restricted from sensitive host actions. Use
+the PIN page to review paired devices, remove a single device, or unpair all
+devices when access should be reset.
+
+Recommended maintainer posture:
+
+- Treat unknown paired devices as untrusted.
+- Unpair devices before sharing logs, fixtures, or VM images.
+- Re-pair clients after major host, certificate, or credential changes.
+
+## Display Mode Override
+
+Display mode override lets a client request a fixed resolution and refresh rate
+for streams where the automatic client-requested mode is not the desired host
+mode.
+
+Use the format:
+
+```text
+1920x1080x60
+```
+
+Leave the field blank to use the client's requested mode. Record any override
+used in bug reports, because display selection, HDR, virtual displays, and
+physical monitor recovery can all affect the final stream mode.
+
+## Client Commands
+
+Client commands allow a paired client to trigger configured host commands when a
+session connects or disconnects.
+
+Use this carefully:
+
+- Keep commands local and explicit.
+- Avoid commands that depend on private paths when sharing configurations.
+- Prefer scripts stored beside the app or inside a documented tools directory.
+- Disable client commands for devices that should only launch apps.
+
+Nimbus inherits much of this behavior from the Apollo and Sunshine lineage. This
+page is the Nimbus-owned reference surface for these controls while deeper docs
+are rebuilt.
diff --git a/packaging/windows/wix/custom_actions.wxs b/packaging/windows/wix/custom_actions.wxs
index 81a45b4dc3..28e76cadee 100644
--- a/packaging/windows/wix/custom_actions.wxs
+++ b/packaging/windows/wix/custom_actions.wxs
@@ -91,7 +91,7 @@
{{ $t('apps.env_vars_about') }}
},
exportLauncherFile(app) {
const link = document.createElement('a');
- const fileContent = `# Artemis app entry
-# Exported by Apollo
-# https://github.com/ClassicOldSong/Apollo
+ const fileContent = `# Lucent app entry
+# Exported by Nimbus
+# https://github.com/kunolabs/Nimbus
[host_uuid] ${this.hostUUID}
[host_name] ${this.hostName}
diff --git a/src_assets/common/assets/web/configs/tabs/AudioVideo.vue b/src_assets/common/assets/web/configs/tabs/AudioVideo.vue
index 227c156c67..e92e941a12 100644
--- a/src_assets/common/assets/web/configs/tabs/AudioVideo.vue
+++ b/src_assets/common/assets/web/configs/tabs/AudioVideo.vue
@@ -25,7 +25,7 @@ const frameLimiterStepLabel = computed(() =>
ddConfigDisabled.value ? t('config.dd_step_3') : t('config.dd_step_4'),
);
-// SudoVDA status mapping (Apollo-specific)
+// SudoVDA status mapping inherited from the host virtual-display driver.
const sudovdaStatus = computed(() => ({
'1': t('config.sudovda_status_unknown'),
'0': t('config.sudovda_status_ready'),
diff --git a/src_assets/common/assets/web/pin.html b/src_assets/common/assets/web/pin.html
index d7661de201..50fa1a412c 100644
--- a/src_assets/common/assets/web/pin.html
+++ b/src_assets/common/assets/web/pin.html
@@ -125,7 +125,7 @@
{{ $t(`pin.client_${cmdType}_cmd_desc`) }}
{{ $t('_common.learn_more') }}
diff --git a/src_assets/windows/misc/service/install-service.bat b/src_assets/windows/misc/service/install-service.bat
index 69e6c40737..a5d30fa109 100644
--- a/src_assets/windows/misc/service/install-service.bat
+++ b/src_assets/windows/misc/service/install-service.bat
@@ -58,10 +58,10 @@ if exist "%SERVICE_CONFIG_FILE%" (
echo Setting service start type set to: [!SERVICE_START_TYPE!]
rem Run the sc command to create/reconfigure the service
-sc %SC_CMD% %SERVICE_NAME% binPath= "\"%SERVICE_BIN%\"" start= %SERVICE_START_TYPE% DisplayName= "Apollo Service"
+sc %SC_CMD% %SERVICE_NAME% binPath= "\"%SERVICE_BIN%\"" start= %SERVICE_START_TYPE% DisplayName= "Nimbus Service"
rem Set the description of the service
-sc description %SERVICE_NAME% "Apollo is a self-hosted game stream host for Moonlight."
+sc description %SERVICE_NAME% "Nimbus is a self-hosted game stream host for Moonlight-compatible clients."
rem Start the new service
net start %SERVICE_NAME%
From 619d88c9a7a2e104b6eb2feb0fe8565eaf4574d3 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 18:02:26 +1000
Subject: [PATCH 16/60] docs: refresh package validation artifacts
---
docs/release-build-audit.md | 17 ++++++++++-------
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 6 +++---
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index c924a6fdb9..11bc3be38a 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -242,17 +242,20 @@ Current visual-design state:
console, amber, green, and red token direction from `docs/ui-identity-plan.md`.
- RTSS and Windows troubleshooting status text now uses Nimbus wording for
user-visible guidance.
+- Tray menu text, launcher export headers, default discovery fallback, service
+ display text, and in-app client-control help links now use Nimbus-owned
+ wording and docs.
## Current Full Package Revalidation
Validation date: 2026-05-21
-Validated source commit: `0b4966f8`
+Validated source commit: `57d01875`
Scope: rebuild the full Windows package after the visible Nimbus web shell,
-static onboarding, Windows status copy, release-note, and release-safety passes.
-This validates generated package artifacts, not installer execution on a target
-machine.
+static onboarding, Windows status copy, remaining visible host-branding cleanup,
+release-note, and release-safety passes. This validates generated package
+artifacts, not installer execution on a target machine.
Command shape:
@@ -268,7 +271,7 @@ Result:
| --- | --- | --- |
| Web UI production build | Pass | Vite still reports inherited large vendor chunk warnings only. |
| CPack WiX MSI | Pass | Initial sandbox run reached WiX but failed ICE validation because Windows Installer service access was unavailable; rerunning outside the sandbox with the same `WIX` path passed. |
-| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.38`, `0b4966f8`, `Kuno Labs`. |
+| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.40`, `57d01875`, `Kuno Labs`. |
| Signing | Skipped | `SIGNPATH_API_TOKEN` was unset; output is unsigned. |
| Installer execution | Pending | Fresh install, uninstall, reinstall, and upgrade behavior still need VM fixture records. |
@@ -276,8 +279,8 @@ Artifacts:
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,360 | `41A5EF596C9C04ACFC792A1A8EB3591CEE970F995A64ABAC80331770C45DA471` |
-| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,741 | `02697C964EA22CA2E7AD840BD355D943ECC59CE64A184F573A12F9B781904F85` |
+| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,360 | `1BE1C58A6128A541F0A9DC49E20186A3D93E3E3C8FFA448A130DD8D5E93D69CF` |
+| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,727 | `9F31155E08353B7788C47FAA7C321C6C25AC4F91B7A557238D1D9B9C9A5B5501` |
Current caveat: these artifacts are newer and better branded than the earlier
`82fa5cdd` validation artifacts, but they are still local validation artifacts
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index 39e09b5f54..872baef3a1 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -68,12 +68,12 @@ Current source validation has passed after the UI and status-message rebrand:
portable binaries and the WiX ICE validation step runs outside the Codex
sandbox.
-Current local package artifacts from commit `0b4966f8`:
+Current local package artifacts from commit `57d01875`:
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `NimbusSetup.exe` | 25,871,360 | `41A5EF596C9C04ACFC792A1A8EB3591CEE970F995A64ABAC80331770C45DA471` |
-| `Nimbus.msi` | 25,606,741 | `02697C964EA22CA2E7AD840BD355D943ECC59CE64A184F573A12F9B781904F85` |
+| `NimbusSetup.exe` | 25,871,360 | `1BE1C58A6128A541F0A9DC49E20186A3D93E3E3C8FFA448A130DD8D5E93D69CF` |
+| `Nimbus.msi` | 25,606,727 | `9F31155E08353B7788C47FAA7C321C6C25AC4F91B7A557238D1D9B9C9A5B5501` |
These are local validation artifacts, not release candidates, until the pending
VM fixture checks below are recorded.
From a0439c6715ae01246d808519daafc12e1d63a3e8 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 18:04:21 +1000
Subject: [PATCH 17/60] docs: update installer fixture candidate
---
docs/windows-installer-fixture.md | 31 +++++++++++++++++++++----------
1 file changed, 21 insertions(+), 10 deletions(-)
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index 0663901f5a..3e86dbcdfa 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -1,6 +1,6 @@
# Nimbus Windows Installer Fixture
-Snapshot date: 2026-05-20
+Snapshot date: 2026-05-21
This fixture is the release gate for the first Nimbus alpha. It is intentionally
separate from the local package build audit: the package build proves that
@@ -28,18 +28,29 @@ flowchart TD
## Candidate Artifact
-The current local package validation produced these artifacts from commit
-`82fa5cdd`:
+The current local package validation produced these artifacts from source commit
+`57d01875`. The documentation commit that records these hashes may be newer than
+the validated source commit.
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,866,752 | `F0C161A08BD9696E500EC694B0723CB769A5E5A0C8E3B031B5838DBCAE4E3338` |
-| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,602,498 | `525AAB47E3539CE29521AC67592996BFA1535E8AE91405442C1A82EAC403FDF1` |
-
-Before tagging `nimbus-v0.1.0-alpha.1`, rebuild the package from the final
-release-prep commit and replace the hashes in the fixture results. The older
-hashes above are proof of the Phase C build, not final release-candidate
-hashes.
+| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,360 | `1BE1C58A6128A541F0A9DC49E20186A3D93E3E3C8FFA448A130DD8D5E93D69CF` |
+| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,727 | `9F31155E08353B7788C47FAA7C321C6C25AC4F91B7A557238D1D9B9C9A5B5501` |
+
+Before tagging `nimbus-v0.1.0-alpha.1`, either use these artifacts for fixture
+testing or rebuild the package from the final release-prep commit and replace
+the hashes here. These are still local validation artifacts until the fixture
+matrix below is recorded.
+
+Current artifact metadata:
+
+| Field | Value |
+| --- | --- |
+| Bootstrapper product | `Nimbus Installer` |
+| File version | `0.0.0.40` |
+| Product version | `57d01875` |
+| Company | `Kuno Labs` |
+| Signing | Unsigned; SignPath skipped because `SIGNPATH_API_TOKEN` is unset |
## Fixture Matrix
From 1bab0532336224234bf1397f02a08bab75b0d2c1 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 18:08:15 +1000
Subject: [PATCH 18/60] ci: pause automatic issue closures
---
.github/workflows/environment-specific-closure.yml | 3 +++
.github/workflows/logs-needed-closure.yml | 3 +++
docs/release-build-audit.md | 8 +++++---
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 2 +-
4 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/environment-specific-closure.yml b/.github/workflows/environment-specific-closure.yml
index 6de309f7b1..e7e69df41b 100644
--- a/.github/workflows/environment-specific-closure.yml
+++ b/.github/workflows/environment-specific-closure.yml
@@ -10,7 +10,10 @@ on:
jobs:
close:
name: Close Environment-Specific Issue
+ # Disabled during Nimbus bootstrap. Re-enable only after the public support
+ # policy clearly defines when maintainers close environment-specific issues.
if: >-
+ false &&
github.event.action == 'labeled' &&
github.event.label.name == 'environment-specific' &&
github.event.issue.state == 'open' &&
diff --git a/.github/workflows/logs-needed-closure.yml b/.github/workflows/logs-needed-closure.yml
index c6cb46a4c2..cf4224a846 100644
--- a/.github/workflows/logs-needed-closure.yml
+++ b/.github/workflows/logs-needed-closure.yml
@@ -13,6 +13,9 @@ concurrency:
jobs:
close:
+ # Disabled during Nimbus bootstrap. Re-enable only after the issue-support
+ # policy, labels, and maintainer response expectations are Nimbus-owned.
+ if: false
runs-on: ubuntu-latest
permissions:
issues: write
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index 11bc3be38a..496eb67064 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -26,10 +26,10 @@ to understand inherited automation before changing release behavior.
| `.github/workflows/ci.yml` | push, pull request, manual | High | Builds Windows and can create GitHub releases from `nimbus-v*` tags. Release creation remains blocked on package-output validation. |
| `.github/workflows/ci-windows.yml` | reusable workflow | High | Builds Windows artifacts, downloads pinned WebRTC artifacts, optionally signs artifacts, and optionally publishes symbols. |
| `.github/workflows/webrtc-release.yml` | manual | High | Can publish pinned WebRTC release assets with `contents: write`. Publishing defaults to off and requires an explicit Nimbus confirmation string. |
-| `.github/workflows/fixed-issue-follow-up.yml` | issue label, release published | Medium | Comments on and closes issues labeled `fixed`. Useful later, but should be reworded and checked before relying on it publicly. |
+| `.github/workflows/fixed-issue-follow-up.yml` | issue label, release published | Medium | Can comment when issues are labeled `fixed`; release-time closure is disabled during Nimbus bootstrap. |
| `.github/workflows/logs-needed-reminder.yml` | issue/comment events | Medium | Uses inherited Vibeshine/Sunshine log filename detection for compatibility. Instructions now use Nimbus wording. |
-| `.github/workflows/logs-needed-closure.yml` | scheduled or issue state flow | Medium | Can close issues for missing logs. Needs maintainer policy review before use. |
-| `.github/workflows/environment-specific-closure.yml` | issue label | Medium | Closes issues as not planned when labeled `environment-specific`. Wording now says Nimbus. |
+| `.github/workflows/logs-needed-closure.yml` | scheduled or issue state flow | Medium | Disabled during Nimbus bootstrap. Re-enable only after maintainer support policy is defined. |
+| `.github/workflows/environment-specific-closure.yml` | issue label | Medium | Disabled during Nimbus bootstrap. Re-enable only after environment-specific closure policy is defined. |
## Release Automation Findings
@@ -68,6 +68,8 @@ Applied hardening:
string.
- Main release creation no longer closes `fixed` issues directly.
- The separate fixed-issue release closer is disabled.
+- Stale logs-needed closure and environment-specific closure jobs are disabled
+ until Nimbus has a public support policy.
Remaining release blocker: the current release-prep commit now builds
Nimbus-named Windows artifacts locally, but a release tag is still blocked until
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index 872baef3a1..269a8112fe 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -17,7 +17,7 @@ has wider testers.
policy, and issue-radar workflow.
- Hardened release automation so public releases require `nimbus-v*` tags.
- Disabled inherited signing, symbol publishing, WebRTC publishing, and
- automatic fixed-issue closure until Nimbus-owned policy and secrets exist.
+ automatic issue-closure paths until Nimbus-owned policy and secrets exist.
- Rebranded public Windows package output to Nimbus, including
`NimbusSetup.exe`, `Nimbus.msi`, Kuno Labs publisher metadata, and Nimbus
support links.
From 0af1f3b89ec2375e46b39e9acc63bfdd2be3590c Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 22:28:00 +1000
Subject: [PATCH 19/60] fix: make uninstaller quick tips mode-aware
---
.../bootstrapper/VibeshineInstaller.cs | 26 ++++++++++++++-----
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/packaging/windows/bootstrapper/VibeshineInstaller.cs b/packaging/windows/bootstrapper/VibeshineInstaller.cs
index e1be133d82..574dac56e5 100644
--- a/packaging/windows/bootstrapper/VibeshineInstaller.cs
+++ b/packaging/windows/bootstrapper/VibeshineInstaller.cs
@@ -527,10 +527,24 @@ public InstallerWindow(InstallerArguments arguments) {
Margin = new Thickness(0, 0, 0, 4)
});
- tipsStack.Children.Add(new TextBlock {
- Text = "You can install or upgrade Nimbus while actively streaming. No system restart is required. "
+ var quickTipsBody = BuildFlavor.IsUninstallOnly
+ ? "Uninstall removes the Nimbus service, firewall rules, and MSI-installed program files. "
+ + "User settings are preserved unless you choose Factory reset in the confirmation step."
+ : "You can install or upgrade Nimbus while actively streaming. No system restart is required. "
+ "After you click Install or Upgrade, the current streaming session will end, then you can usually "
- + "start streaming again after about 1–2 minutes without issues.",
+ + "start streaming again after about 1–2 minutes without issues.";
+ var quickTipsCommandIntro = BuildFlavor.IsUninstallOnly
+ ? "You can also uninstall from an elevated shell:"
+ : "You can also install from an SSH session on this host (run in an elevated shell):";
+ var quickTipsCommand = BuildFlavor.IsUninstallOnly
+ ? "NimbusSetup.exe /uninstall /quiet"
+ : "NimbusSetup.exe /qn /norestart";
+ var quickTipsFooter = BuildFlavor.IsUninstallOnly
+ ? "Click Uninstall Nimbus to choose removal options."
+ : "Click the buttons below to proceed.";
+
+ tipsStack.Children.Add(new TextBlock {
+ Text = quickTipsBody,
FontSize = 12.5,
Foreground = new SolidColorBrush(Color.FromRgb(211, 220, 246)),
Margin = new Thickness(0, 0, 0, 10),
@@ -538,7 +552,7 @@ public InstallerWindow(InstallerArguments arguments) {
});
tipsStack.Children.Add(new TextBlock {
- Text = "You can also install from an SSH session on this host (run in an elevated shell):",
+ Text = quickTipsCommandIntro,
FontSize = 13,
Foreground = new SolidColorBrush(Color.FromRgb(203, 219, 241)),
Margin = new Thickness(0, 0, 0, 6),
@@ -546,7 +560,7 @@ public InstallerWindow(InstallerArguments arguments) {
});
tipsStack.Children.Add(new TextBox {
- Text = "NimbusSetup.exe /qn /norestart",
+ Text = quickTipsCommand,
IsReadOnly = true,
FontFamily = new FontFamily("Consolas"),
FontSize = 12.5,
@@ -559,7 +573,7 @@ public InstallerWindow(InstallerArguments arguments) {
});
tipsStack.Children.Add(new TextBlock {
- Text = "Click the buttons below to proceed.",
+ Text = quickTipsFooter,
FontSize = 12.5,
Foreground = new SolidColorBrush(Color.FromRgb(211, 220, 246)),
Margin = new Thickness(0, 0, 0, 0),
From 50cad79df359754653289a4875c7e3fb0bf6c77f Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 22:30:46 +1000
Subject: [PATCH 20/60] docs: refresh quick tip package candidate
---
docs/release-build-audit.md | 15 +++++++++------
docs/windows-installer-fixture.md | 10 +++++-----
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 8 +++++---
3 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index 496eb67064..7d2379d1b0 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -247,17 +247,20 @@ Current visual-design state:
- Tray menu text, launcher export headers, default discovery fallback, service
display text, and in-app client-control help links now use Nimbus-owned
wording and docs.
+- The uninstaller quick-tip panel now uses uninstall-specific copy instead of
+ reusing install/upgrade guidance.
## Current Full Package Revalidation
Validation date: 2026-05-21
-Validated source commit: `57d01875`
+Validated source commit: `0af1f3b8`
Scope: rebuild the full Windows package after the visible Nimbus web shell,
static onboarding, Windows status copy, remaining visible host-branding cleanup,
-release-note, and release-safety passes. This validates generated package
-artifacts, not installer execution on a target machine.
+uninstaller quick-tip copy, release-note, and release-safety passes. This
+validates generated package artifacts, not installer execution on a target
+machine.
Command shape:
@@ -273,7 +276,7 @@ Result:
| --- | --- | --- |
| Web UI production build | Pass | Vite still reports inherited large vendor chunk warnings only. |
| CPack WiX MSI | Pass | Initial sandbox run reached WiX but failed ICE validation because Windows Installer service access was unavailable; rerunning outside the sandbox with the same `WIX` path passed. |
-| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.40`, `57d01875`, `Kuno Labs`. |
+| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.41`, `0af1f3b8`, `Kuno Labs`. |
| Signing | Skipped | `SIGNPATH_API_TOKEN` was unset; output is unsigned. |
| Installer execution | Pending | Fresh install, uninstall, reinstall, and upgrade behavior still need VM fixture records. |
@@ -281,8 +284,8 @@ Artifacts:
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,360 | `1BE1C58A6128A541F0A9DC49E20186A3D93E3E3C8FFA448A130DD8D5E93D69CF` |
-| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,727 | `9F31155E08353B7788C47FAA7C321C6C25AC4F91B7A557238D1D9B9C9A5B5501` |
+| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,872 | `4091BACCA4CF23356C583956606D18451D3516ABDA8D35438996A9693BE66F20` |
+| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,719 | `6B348D3516352DE46690940A0241B9DB38B1FA4F56ECF856A4BE7E52BE7A63EC` |
Current caveat: these artifacts are newer and better branded than the earlier
`82fa5cdd` validation artifacts, but they are still local validation artifacts
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index 3e86dbcdfa..29ee0bb010 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -29,13 +29,13 @@ flowchart TD
## Candidate Artifact
The current local package validation produced these artifacts from source commit
-`57d01875`. The documentation commit that records these hashes may be newer than
+`0af1f3b8`. The documentation commit that records these hashes may be newer than
the validated source commit.
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,360 | `1BE1C58A6128A541F0A9DC49E20186A3D93E3E3C8FFA448A130DD8D5E93D69CF` |
-| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,727 | `9F31155E08353B7788C47FAA7C321C6C25AC4F91B7A557238D1D9B9C9A5B5501` |
+| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,872 | `4091BACCA4CF23356C583956606D18451D3516ABDA8D35438996A9693BE66F20` |
+| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,719 | `6B348D3516352DE46690940A0241B9DB38B1FA4F56ECF856A4BE7E52BE7A63EC` |
Before tagging `nimbus-v0.1.0-alpha.1`, either use these artifacts for fixture
testing or rebuild the package from the final release-prep commit and replace
@@ -47,8 +47,8 @@ Current artifact metadata:
| Field | Value |
| --- | --- |
| Bootstrapper product | `Nimbus Installer` |
-| File version | `0.0.0.40` |
-| Product version | `57d01875` |
+| File version | `0.0.0.41` |
+| Product version | `0af1f3b8` |
| Company | `Kuno Labs` |
| Signing | Unsigned; SignPath skipped because `SIGNPATH_API_TOKEN` is unset |
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index 269a8112fe..d10f7a45fe 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -35,6 +35,8 @@ has wider testers.
- Retargeted user-visible tray, launcher export, service display, fallback host
naming, and in-app client-control help surfaces to Nimbus-owned wording and
docs.
+- Made the uninstaller quick-tip panel uninstall-specific instead of showing
+ install/upgrade guidance.
## Compatibility Notes
@@ -68,12 +70,12 @@ Current source validation has passed after the UI and status-message rebrand:
portable binaries and the WiX ICE validation step runs outside the Codex
sandbox.
-Current local package artifacts from commit `57d01875`:
+Current local package artifacts from commit `0af1f3b8`:
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `NimbusSetup.exe` | 25,871,360 | `1BE1C58A6128A541F0A9DC49E20186A3D93E3E3C8FFA448A130DD8D5E93D69CF` |
-| `Nimbus.msi` | 25,606,727 | `9F31155E08353B7788C47FAA7C321C6C25AC4F91B7A557238D1D9B9C9A5B5501` |
+| `NimbusSetup.exe` | 25,871,872 | `4091BACCA4CF23356C583956606D18451D3516ABDA8D35438996A9693BE66F20` |
+| `Nimbus.msi` | 25,606,719 | `6B348D3516352DE46690940A0241B9DB38B1FA4F56ECF856A4BE7E52BE7A63EC` |
These are local validation artifacts, not release candidates, until the pending
VM fixture checks below are recorded.
From c26adb5c2a365c42f8c9ecae23dd1926ab1ceaa5 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 22:42:13 +1000
Subject: [PATCH 21/60] docs: record partial Windows fixture evidence
---
docs/release-build-audit.md | 9 ++++--
docs/windows-installer-fixture.md | 30 +++++++++++++++++++
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 20 +++++++++----
3 files changed, 51 insertions(+), 8 deletions(-)
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index 7d2379d1b0..35a5882691 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -278,7 +278,7 @@ Result:
| CPack WiX MSI | Pass | Initial sandbox run reached WiX but failed ICE validation because Windows Installer service access was unavailable; rerunning outside the sandbox with the same `WIX` path passed. |
| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.41`, `0af1f3b8`, `Kuno Labs`. |
| Signing | Skipped | `SIGNPATH_API_TOKEN` was unset; output is unsigned. |
-| Installer execution | Pending | Fresh install, uninstall, reinstall, and upgrade behavior still need VM fixture records. |
+| Installer execution | Partial | Manual VM smoke observed Nimbus default install path, visible Nimbus wording, service running with Nimbus description, Web UI launch path, and no Defender warning. Uninstall/reinstall, client pairing, streaming, and upgrade behavior still need fixture records. |
Artifacts:
@@ -289,7 +289,8 @@ Artifacts:
Current caveat: these artifacts are newer and better branded than the earlier
`82fa5cdd` validation artifacts, but they are still local validation artifacts
-until VM install and upgrade evidence is recorded.
+until the remaining VM uninstall, reinstall, pairing, stream, and upgrade
+evidence is recorded.
## Required Secrets Before Release CI
@@ -301,7 +302,9 @@ until VM install and upgrade evidence is recorded.
## Recommended Next Actions
-1. Run installer dry-runs in a Windows VM or snapshot fixture.
+1. Finish the Windows VM fixture: uninstaller quick-tip retest, uninstall,
+ reinstall, compatible-client pairing, short stream smoke, and upgrade checks
+ where practical.
2. Prepare the first alpha release notes for `nimbus-v0.1.0-alpha.1`.
3. Review issue automation policy before enabling automatic issue closures.
4. Create a Nimbus symbol publishing plan before enabling `publish_symbols`.
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index 29ee0bb010..603199979b 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -67,6 +67,36 @@ Current artifact metadata:
| Coexistence with Sunshine | Optional for alpha | Pending | Record whether install replaces or coexists |
| Windows SmartScreen/AV behavior | Yes | Pending | Unsigned prompt or false-positive notes recorded |
+## Partial Manual Fixture Notes
+
+Date: 2026-05-21
+
+Candidate artifact: `NimbusSetup.exe` from source commit `0af1f3b8`
+(`0.0.0.41`). These notes summarize the maintainer VM smoke loop. Screenshots
+and fixture handoff folders are local validation evidence and are not committed
+to the public repository.
+
+Observed so far:
+
+| Check | Status | Notes |
+| --- | --- | --- |
+| Default install path | Observed pass | Fresh install defaults to `C:\Program Files\Nimbus`. |
+| Visible installer and app branding | Observed pass | Maintainer-confirmed visible checks use Nimbus wording, including installer surfaces and Web UI/dashboard copy. |
+| Windows service after install | Observed compatibility pass | Service is running. Internal service name remains `ApolloService`; visible service description is `Nimbus Service`. |
+| Web UI launch path | Observed pass | Tray context menu can open the local Web UI. Browser certificate warning is expected for the inherited local HTTPS flow. |
+| Uninstall confirmation modal | Observed pass | Modal copy correctly describes uninstall options and factory-reset behavior. |
+| Uninstaller quick tips | Fixed, retest pending | An older candidate reused install/upgrade tips in uninstall mode. Fixed in `0af1f3b8`; retest with `0.0.0.41`. |
+| Windows Defender prompt | Observed pass | Maintainer reported no Defender warning during the install smoke. |
+
+Still blocking the alpha gate:
+
+- Confirm the `0.0.0.41` uninstaller quick tips show uninstall-specific copy.
+- Confirm uninstall removes or stops the service and removes the Add/Remove
+ Programs entry.
+- Confirm reinstall after uninstall completes without manual cleanup.
+- Run at least one compatible-client pairing and short stream smoke.
+- Record upgrade behavior from Apollo and/or Vibepollo where practical.
+
## Evidence Commands
The recommended path is to run the evidence collector before install, after
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index d10f7a45fe..885353f00b 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -77,16 +77,26 @@ Current local package artifacts from commit `0af1f3b8`:
| `NimbusSetup.exe` | 25,871,872 | `4091BACCA4CF23356C583956606D18451D3516ABDA8D35438996A9693BE66F20` |
| `Nimbus.msi` | 25,606,719 | `6B348D3516352DE46690940A0241B9DB38B1FA4F56ECF856A4BE7E52BE7A63EC` |
-These are local validation artifacts, not release candidates, until the pending
-VM fixture checks below are recorded.
+These are local validation artifacts, not release candidates, until the VM
+fixture checks below are completed and recorded.
+
+Partial manual VM observations from the current candidate loop:
+
+- Fresh install defaults to `C:\Program Files\Nimbus`.
+- Visible installer, tray-opened Web UI, first-run, dashboard, and uninstall
+ confirmation surfaces use Nimbus wording.
+- The installed service runs with Nimbus user-visible description text while
+ preserving the inherited internal `ApolloService` service name for this alpha.
+- No Microsoft Defender warning was observed during the manual install smoke.
+- The uninstaller quick-tip panel was fixed after VM feedback and still needs a
+ retest with the `0.0.0.41` candidate.
Pending before release:
-- Fresh install in a Windows VM or snapshot fixture.
-- Web UI launch after install.
+- Retest the `0.0.0.41` uninstaller quick-tip copy.
+- Uninstall and reinstall behavior.
- Compatible-client pairing smoke.
- Short local-network stream smoke.
-- Uninstall and reinstall behavior.
- Upgrade behavior from Apollo and/or Vibepollo where practical.
## Known Issues And Caveats
From 0ca31ee512deb196eb3c0e5a85301ffd53f0fd3a Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 22:44:54 +1000
Subject: [PATCH 22/60] fix: retarget English session tooltips
---
src_assets/common/assets/web/public/assets/locale/en.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json
index 0b37263424..77a6058a10 100644
--- a/src_assets/common/assets/web/public/assets/locale/en.json
+++ b/src_assets/common/assets/web/public/assets/locale/en.json
@@ -892,7 +892,7 @@
"tip_resolution": "Stream resolution (width × height in pixels) negotiated with the client.",
"tip_fps": "Target frames-per-second the encoder is asked to produce.",
"tip_bitrate": "Target video bitrate in megabits per second (Mbps).",
- "tip_bitrate_dual": "Top: the bandwidth budget you set on the client (e.g. 40 Mbps in Moonlight). Bottom (encode): what's left for the video encoder after Sunshine subtracts FEC error-correction (~20% by default), audio (~192 kbps), and ~500 kbps of control overhead. This is normal and expected.",
+ "tip_bitrate_dual": "Top: the bandwidth budget you set on the client (e.g. 40 Mbps in Moonlight). Bottom (encode): what's left for the video encoder after Nimbus subtracts FEC error-correction (~20% by default), audio (~192 kbps), and ~500 kbps of control overhead. This is normal and expected.",
"tip_codec": "Video codec used for this session (H.264, HEVC, or AV1).",
"tip_audio_channels": "Number of audio channels (e.g. 2ch = stereo, 6ch = 5.1 surround).",
"tip_encode_latency": "Time the GPU/CPU spent encoding the latest frame. <8ms is excellent, 8–16ms acceptable, >16ms means encoder can't keep up.",
@@ -916,10 +916,10 @@
"tip_last_audio": "Time since the last audio packet was sent. Should be < 100ms while streaming.",
"tip_history_client": "Friendly name of the client app (e.g. Moonlight on a specific device).",
"tip_history_device": "Hardware/OS device name reported by the client.",
- "tip_history_app": "The Sunshine application that was launched for this session.",
+ "tip_history_app": "The Nimbus application that was launched for this session.",
"tip_history_duration": "How long the streaming session lasted from start to disconnect.",
"tip_history_server_version": "Nimbus version recorded when this stream started.",
- "tip_history_bitrate": "The wire-bandwidth budget the client requested for this session. The encoder may have used slightly less after Sunshine subtracted FEC and audio overhead.",
+ "tip_history_bitrate": "The wire-bandwidth budget the client requested for this session. The encoder may have used slightly less after Nimbus subtracted FEC and audio overhead.",
"tip_chart_encode_latency": "How long the GPU/CPU spent encoding each frame, sampled every ~2 seconds. Consistently above 16ms means the encoder is struggling to keep up.",
"tip_chart_throughput": "Average outgoing video+audio bitrate in megabits per second, computed from byte deltas between samples. Should hover near the target bitrate.",
"tip_chart_quality": "Connection-quality events: client-reported packet losses, IDR (full-frame) requests, and reference-frame invalidations. Spikes indicate network problems.",
From 4f3411b25b144d9578e3a63b10b9a64020e87d94 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 22:48:35 +1000
Subject: [PATCH 23/60] fix: show manual update check feedback
---
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 3 ++
src/system_tray.cpp | 2 +-
src/update.cpp | 54 +++++++++++++++++--
src/update.h | 2 +-
4 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index 885353f00b..3296295b21 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -37,6 +37,9 @@ has wider testers.
docs.
- Made the uninstaller quick-tip panel uninstall-specific instead of showing
install/upgrade guidance.
+- Added user-visible tray feedback for manual update checks so `Check for
+ Update` reports checking, already-running, no-release, up-to-date, or failure
+ status instead of only writing to logs.
## Compatibility Notes
diff --git a/src/system_tray.cpp b/src/system_tray.cpp
index 8b074998b7..68c0472c35 100644
--- a/src/system_tray.cpp
+++ b/src/system_tray.cpp
@@ -153,7 +153,7 @@ namespace system_tray {
{.text = TRAY_MSG_NO_APP_RUNNING, .cb = tray_force_stop_cb},
{.text = "Check for Update", .cb = [](tray_menu *) {
BOOST_LOG(info) << "Manual update check requested from tray"sv;
- update::trigger_check(true);
+ update::trigger_check(true, true);
}},
{.text = "Restart", .cb = tray_restart_cb},
diff --git a/src/update.cpp b/src/update.cpp
index 2085f5192b..90fedc0eff 100644
--- a/src/update.cpp
+++ b/src/update.cpp
@@ -50,7 +50,7 @@ namespace update {
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Accept: application/vnd.github+json");
headers = curl_slist_append(headers, "X-GitHub-Api-Version: 2022-11-28");
- headers = curl_slist_append(headers, "User-Agent: Sunshine-Updater/1.0");
+ headers = curl_slist_append(headers, "User-Agent: Nimbus-Updater/1.0");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
bool tls_configured = http::configure_curl_tls(curl);
@@ -113,7 +113,16 @@ namespace update {
// We intentionally allow repeated notifications; do not persist last_notified_version
}
- static void perform_check() {
+ static void notify_manual_update_check(const std::string &title, const std::string &body) {
+#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
+ system_tray::tray_notify(title.c_str(), body.c_str());
+#else
+ (void) title;
+ (void) body;
+#endif
+ }
+
+ static void perform_check(bool notify_manual_result) {
state.check_in_progress = true;
auto fg = util::fail_guard([]() {
state.check_in_progress = false;
@@ -125,7 +134,9 @@ namespace update {
BOOST_LOG(info) << "Update check: querying GitHub releases from repo "sv
<< SUNSHINE_REPO_OWNER << '/' << SUNSHINE_REPO_NAME;
std::string releases_json;
+ bool release_query_ok = false;
if (download_github_release_data(SUNSHINE_REPO_OWNER, SUNSHINE_REPO_NAME, releases_json)) {
+ release_query_ok = true;
auto j = nlohmann::json::parse(releases_json);
// Reset release info
state.latest_release = release_info_t {};
@@ -193,6 +204,9 @@ namespace update {
if (!state.latest_prerelease.version.empty()) {
BOOST_LOG(info) << "Update check: latest prerelease tag="sv << state.latest_prerelease.version;
}
+ } else {
+ state.latest_release = release_info_t {};
+ state.latest_prerelease = release_info_t {};
}
state.last_check_time = std::chrono::steady_clock::now();
@@ -220,16 +234,41 @@ namespace update {
BOOST_LOG(info) << "Update check (tag-based): up-to-date. installed="sv << installed_version_tag
<< ", stable="sv << latest_stable_tag
<< ", prerelease="sv << latest_pre_tag;
+ if (notify_manual_result) {
+ if (!release_query_ok) {
+ notify_manual_update_check(
+ "Nimbus update check failed",
+ "Could not reach the Nimbus releases feed. See the Nimbus logs for details.");
+ } else if (latest_stable_tag.empty() && latest_pre_tag.empty()) {
+ notify_manual_update_check(
+ "Nimbus update check complete",
+ "No Nimbus releases are published yet.");
+ } else {
+ notify_manual_update_check(
+ "Nimbus update check complete",
+ "No newer Nimbus release was found.");
+ }
+ }
}
} catch (std::exception &e) {
BOOST_LOG(warning) << "Update check failed: "sv << e.what();
+ if (notify_manual_result) {
+ notify_manual_update_check(
+ "Nimbus update check failed",
+ "Could not check Nimbus releases. See the Nimbus logs for details.");
+ }
}
}
- void trigger_check(bool force) {
+ void trigger_check(bool force, bool notify_manual_result) {
const bool in_progress = state.check_in_progress.load();
if (in_progress) {
BOOST_LOG(info) << "Update check trigger skipped: another check is in progress (force="sv << (force ? "true"sv : "false"sv) << ')';
+ if (notify_manual_result) {
+ notify_manual_update_check(
+ "Nimbus update check",
+ "An update check is already running.");
+ }
return;
}
if (!force && config::sunshine.update_check_interval_seconds == 0) {
@@ -245,8 +284,13 @@ namespace update {
}
}
BOOST_LOG(info) << "Update check trigger accepted (force="sv << (force ? "true"sv : "false"sv) << ')';
- std::thread([]() {
- perform_check();
+ if (notify_manual_result) {
+ notify_manual_update_check(
+ "Nimbus update check",
+ "Checking for Nimbus releases...");
+ }
+ std::thread([notify_manual_result]() {
+ perform_check(notify_manual_result);
}).detach();
}
diff --git a/src/update.h b/src/update.h
index 7e33075edf..f6eb15891b 100644
--- a/src/update.h
+++ b/src/update.h
@@ -47,7 +47,7 @@ namespace update {
* Initiates a check for updates if not already running. If force is true, bypasses interval throttling.
* @param force If true, forces the check regardless of throttling.
*/
- void trigger_check(bool force);
+ void trigger_check(bool force, bool notify_manual_result = false);
/**
* @brief Handle stream start event for update notification.
From 8ebf1eac040e86dec57da792aadf093e4a172b27 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 22:53:15 +1000
Subject: [PATCH 24/60] docs: refresh Windows package candidate
---
docs/release-build-audit.md | 14 +++++------
docs/windows-installer-fixture.md | 25 +++++++++++--------
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 15 ++++++-----
3 files changed, 30 insertions(+), 24 deletions(-)
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index 35a5882691..881d8f67f2 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -254,13 +254,13 @@ Current visual-design state:
Validation date: 2026-05-21
-Validated source commit: `0af1f3b8`
+Validated source commit: `4f3411b2`
Scope: rebuild the full Windows package after the visible Nimbus web shell,
static onboarding, Windows status copy, remaining visible host-branding cleanup,
-uninstaller quick-tip copy, release-note, and release-safety passes. This
-validates generated package artifacts, not installer execution on a target
-machine.
+uninstaller quick-tip copy, manual update-check feedback, English session
+tooltip polish, release-note, and release-safety passes. This validates
+generated package artifacts, not installer execution on a target machine.
Command shape:
@@ -276,7 +276,7 @@ Result:
| --- | --- | --- |
| Web UI production build | Pass | Vite still reports inherited large vendor chunk warnings only. |
| CPack WiX MSI | Pass | Initial sandbox run reached WiX but failed ICE validation because Windows Installer service access was unavailable; rerunning outside the sandbox with the same `WIX` path passed. |
-| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.41`, `0af1f3b8`, `Kuno Labs`. |
+| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.44`, `4f3411b2`, `Kuno Labs`. |
| Signing | Skipped | `SIGNPATH_API_TOKEN` was unset; output is unsigned. |
| Installer execution | Partial | Manual VM smoke observed Nimbus default install path, visible Nimbus wording, service running with Nimbus description, Web UI launch path, and no Defender warning. Uninstall/reinstall, client pairing, streaming, and upgrade behavior still need fixture records. |
@@ -284,8 +284,8 @@ Artifacts:
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,872 | `4091BACCA4CF23356C583956606D18451D3516ABDA8D35438996A9693BE66F20` |
-| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,719 | `6B348D3516352DE46690940A0241B9DB38B1FA4F56ECF856A4BE7E52BE7A63EC` |
+| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,872 | `EEAD1749BA88032AFD09E7FBB1917B50DDA88F425059CEEDC18775ADE3028328` |
+| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,727 | `6E739CE9F56B11A0FD5B824E460AB389A0C61216FEE2CCE8DAA30E1E27F48D4E` |
Current caveat: these artifacts are newer and better branded than the earlier
`82fa5cdd` validation artifacts, but they are still local validation artifacts
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index 603199979b..77cf563fd3 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -29,13 +29,13 @@ flowchart TD
## Candidate Artifact
The current local package validation produced these artifacts from source commit
-`0af1f3b8`. The documentation commit that records these hashes may be newer than
+`4f3411b2`. The documentation commit that records these hashes may be newer than
the validated source commit.
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,872 | `4091BACCA4CF23356C583956606D18451D3516ABDA8D35438996A9693BE66F20` |
-| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,719 | `6B348D3516352DE46690940A0241B9DB38B1FA4F56ECF856A4BE7E52BE7A63EC` |
+| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,872 | `EEAD1749BA88032AFD09E7FBB1917B50DDA88F425059CEEDC18775ADE3028328` |
+| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,727 | `6E739CE9F56B11A0FD5B824E460AB389A0C61216FEE2CCE8DAA30E1E27F48D4E` |
Before tagging `nimbus-v0.1.0-alpha.1`, either use these artifacts for fixture
testing or rebuild the package from the final release-prep commit and replace
@@ -47,8 +47,8 @@ Current artifact metadata:
| Field | Value |
| --- | --- |
| Bootstrapper product | `Nimbus Installer` |
-| File version | `0.0.0.41` |
-| Product version | `0af1f3b8` |
+| File version | `0.0.0.44` |
+| Product version | `4f3411b2` |
| Company | `Kuno Labs` |
| Signing | Unsigned; SignPath skipped because `SIGNPATH_API_TOKEN` is unset |
@@ -71,10 +71,11 @@ Current artifact metadata:
Date: 2026-05-21
-Candidate artifact: `NimbusSetup.exe` from source commit `0af1f3b8`
-(`0.0.0.41`). These notes summarize the maintainer VM smoke loop. Screenshots
-and fixture handoff folders are local validation evidence and are not committed
-to the public repository.
+Current candidate artifact: `NimbusSetup.exe` from source commit `4f3411b2`
+(`0.0.0.44`). The observations below were gathered during the maintainer VM
+smoke loop on the immediately preceding candidate series. Screenshots and
+fixture handoff folders are local validation evidence and are not committed to
+the public repository.
Observed so far:
@@ -85,12 +86,14 @@ Observed so far:
| Windows service after install | Observed compatibility pass | Service is running. Internal service name remains `ApolloService`; visible service description is `Nimbus Service`. |
| Web UI launch path | Observed pass | Tray context menu can open the local Web UI. Browser certificate warning is expected for the inherited local HTTPS flow. |
| Uninstall confirmation modal | Observed pass | Modal copy correctly describes uninstall options and factory-reset behavior. |
-| Uninstaller quick tips | Fixed, retest pending | An older candidate reused install/upgrade tips in uninstall mode. Fixed in `0af1f3b8`; retest with `0.0.0.41`. |
+| Uninstaller quick tips | Fixed, retest pending | An older candidate reused install/upgrade tips in uninstall mode. Fixed in `0af1f3b8`; retest with the current `0.0.0.44` candidate. |
+| Manual tray update check | Fixed, retest pending | `Check for Update` now reports manual tray feedback from `4f3411b2`; retest in the VM. |
| Windows Defender prompt | Observed pass | Maintainer reported no Defender warning during the install smoke. |
Still blocking the alpha gate:
-- Confirm the `0.0.0.41` uninstaller quick tips show uninstall-specific copy.
+- Confirm the `0.0.0.44` uninstaller quick tips show uninstall-specific copy.
+- Confirm the `Check for Update` tray action shows manual feedback.
- Confirm uninstall removes or stops the service and removes the Add/Remove
Programs entry.
- Confirm reinstall after uninstall completes without manual cleanup.
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index 3296295b21..cbd36b9ca9 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -73,17 +73,17 @@ Current source validation has passed after the UI and status-message rebrand:
portable binaries and the WiX ICE validation step runs outside the Codex
sandbox.
-Current local package artifacts from commit `0af1f3b8`:
+Current local package artifacts from commit `4f3411b2`:
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `NimbusSetup.exe` | 25,871,872 | `4091BACCA4CF23356C583956606D18451D3516ABDA8D35438996A9693BE66F20` |
-| `Nimbus.msi` | 25,606,719 | `6B348D3516352DE46690940A0241B9DB38B1FA4F56ECF856A4BE7E52BE7A63EC` |
+| `NimbusSetup.exe` | 25,871,872 | `EEAD1749BA88032AFD09E7FBB1917B50DDA88F425059CEEDC18775ADE3028328` |
+| `Nimbus.msi` | 25,606,727 | `6E739CE9F56B11A0FD5B824E460AB389A0C61216FEE2CCE8DAA30E1E27F48D4E` |
These are local validation artifacts, not release candidates, until the VM
fixture checks below are completed and recorded.
-Partial manual VM observations from the current candidate loop:
+Partial manual VM observations from the previous candidate loop:
- Fresh install defaults to `C:\Program Files\Nimbus`.
- Visible installer, tray-opened Web UI, first-run, dashboard, and uninstall
@@ -92,11 +92,14 @@ Partial manual VM observations from the current candidate loop:
preserving the inherited internal `ApolloService` service name for this alpha.
- No Microsoft Defender warning was observed during the manual install smoke.
- The uninstaller quick-tip panel was fixed after VM feedback and still needs a
- retest with the `0.0.0.41` candidate.
+ retest with the `0.0.0.44` candidate.
+- Manual tray update-check feedback was added after VM feedback and needs a
+ retest with the `0.0.0.44` candidate.
Pending before release:
-- Retest the `0.0.0.41` uninstaller quick-tip copy.
+- Retest the `0.0.0.44` uninstaller quick-tip copy.
+- Retest manual `Check for Update` tray feedback.
- Uninstall and reinstall behavior.
- Compatible-client pairing smoke.
- Short local-network stream smoke.
From 37fd3573a6154bebfc5526ca20ff028904d90f99 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 23:00:02 +1000
Subject: [PATCH 25/60] docs: clarify alpha version display policy
---
docs/release-process.md | 15 +++++++++++++++
docs/windows-installer-fixture.md | 7 +++++++
2 files changed, 22 insertions(+)
diff --git a/docs/release-process.md b/docs/release-process.md
index f28e0eabdf..c7f6bbe4d5 100644
--- a/docs/release-process.md
+++ b/docs/release-process.md
@@ -111,6 +111,21 @@ Preconditions before creating the tag:
| WebRTC assets | WebRTC publishing remains manual and confirmation-gated. |
| Issue automation | Automatic issue closure remains disabled. |
+Version display policy:
+
+- Pre-tag VM candidates may display `0.0.0` in the installer, Web UI, or
+ Programs & Features because the repository default version remains `0.0.0`
+ until a Nimbus tag or explicit build version is provided.
+- Do not publish public release artifacts from an unversioned configure/build.
+- The final `nimbus-v0.1.0-alpha.1` package must be configured from the
+ annotated tag or with an explicit `TAG=nimbus-v0.1.0-alpha.1` build
+ environment before packaging.
+- Windows Installer `ProductVersion` is numeric-only, so Programs & Features may
+ show the MSI-safe base version such as `0.1.0` or `0.1.0.0` even when the
+ user-facing release tag is `0.1.0-alpha.1`.
+- File metadata may include a fourth numeric build/revision component, such as
+ `0.1.0.12`, for Windows upgrade ordering and local candidate inspection.
+
When all preconditions pass, create and push only the intended tag:
```bash
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index 77cf563fd3..3bbca322e2 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -52,6 +52,13 @@ Current artifact metadata:
| Company | `Kuno Labs` |
| Signing | Unsigned; SignPath skipped because `SIGNPATH_API_TOKEN` is unset |
+Version caveat: this is a pre-tag fixture candidate. It may display `0.0.0` in
+the installer, Web UI, or Programs & Features even though file metadata includes
+the generated four-part Windows file version above. That is acceptable for
+local VM validation only. Public alpha artifacts must be rebuilt from the
+`nimbus-v0.1.0-alpha.1` tag, or an equivalent explicit `TAG` build environment,
+so user-facing version surfaces no longer look like an unversioned build.
+
## Fixture Matrix
| Scenario | Required before alpha? | Status | Evidence |
From 9b7636acc6522597de26c2da61c76aff8a38733d Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 23:25:32 +1000
Subject: [PATCH 26/60] docs: record update check fixture pass
---
docs/release-build-audit.md | 2 +-
docs/windows-installer-fixture.md | 3 +--
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 4 +---
3 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index 881d8f67f2..416ee29281 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -278,7 +278,7 @@ Result:
| CPack WiX MSI | Pass | Initial sandbox run reached WiX but failed ICE validation because Windows Installer service access was unavailable; rerunning outside the sandbox with the same `WIX` path passed. |
| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.44`, `4f3411b2`, `Kuno Labs`. |
| Signing | Skipped | `SIGNPATH_API_TOKEN` was unset; output is unsigned. |
-| Installer execution | Partial | Manual VM smoke observed Nimbus default install path, visible Nimbus wording, service running with Nimbus description, Web UI launch path, and no Defender warning. Uninstall/reinstall, client pairing, streaming, and upgrade behavior still need fixture records. |
+| Installer execution | Partial | Manual VM smoke observed Nimbus default install path, visible Nimbus wording, service running with Nimbus description, Web UI launch path, manual update-check feedback, and no Defender warning. Uninstall/reinstall, client pairing, streaming, and upgrade behavior still need fixture records. |
Artifacts:
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index 3bbca322e2..5808c6128d 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -94,13 +94,12 @@ Observed so far:
| Web UI launch path | Observed pass | Tray context menu can open the local Web UI. Browser certificate warning is expected for the inherited local HTTPS flow. |
| Uninstall confirmation modal | Observed pass | Modal copy correctly describes uninstall options and factory-reset behavior. |
| Uninstaller quick tips | Fixed, retest pending | An older candidate reused install/upgrade tips in uninstall mode. Fixed in `0af1f3b8`; retest with the current `0.0.0.44` candidate. |
-| Manual tray update check | Fixed, retest pending | `Check for Update` now reports manual tray feedback from `4f3411b2`; retest in the VM. |
+| Manual tray update check | Observed pass | Maintainer confirmed the `Check for Update` tray action shows visible feedback in the VM. |
| Windows Defender prompt | Observed pass | Maintainer reported no Defender warning during the install smoke. |
Still blocking the alpha gate:
- Confirm the `0.0.0.44` uninstaller quick tips show uninstall-specific copy.
-- Confirm the `Check for Update` tray action shows manual feedback.
- Confirm uninstall removes or stops the service and removes the Add/Remove
Programs entry.
- Confirm reinstall after uninstall completes without manual cleanup.
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index cbd36b9ca9..f374495b37 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -93,13 +93,11 @@ Partial manual VM observations from the previous candidate loop:
- No Microsoft Defender warning was observed during the manual install smoke.
- The uninstaller quick-tip panel was fixed after VM feedback and still needs a
retest with the `0.0.0.44` candidate.
-- Manual tray update-check feedback was added after VM feedback and needs a
- retest with the `0.0.0.44` candidate.
+- Manual tray update-check feedback is visible in the VM.
Pending before release:
- Retest the `0.0.0.44` uninstaller quick-tip copy.
-- Retest manual `Check for Update` tray feedback.
- Uninstall and reinstall behavior.
- Compatible-client pairing smoke.
- Short local-network stream smoke.
From 6914f6e4246160579b22b3bd2fb7b9b09e5a5c17 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 23:39:29 +1000
Subject: [PATCH 27/60] fix: deep link pairing notification
---
docs/release-build-audit.md | 2 +-
docs/windows-installer-fixture.md | 8 +-
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 4 +-
src/system_tray.cpp | 2 +-
.../assets/web/views/ClientManagementView.vue | 186 ++++++++++--------
5 files changed, 111 insertions(+), 91 deletions(-)
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index 416ee29281..20258ba07f 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -278,7 +278,7 @@ Result:
| CPack WiX MSI | Pass | Initial sandbox run reached WiX but failed ICE validation because Windows Installer service access was unavailable; rerunning outside the sandbox with the same `WIX` path passed. |
| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.44`, `4f3411b2`, `Kuno Labs`. |
| Signing | Skipped | `SIGNPATH_API_TOKEN` was unset; output is unsigned. |
-| Installer execution | Partial | Manual VM smoke observed Nimbus default install path, visible Nimbus wording, service running with Nimbus description, Web UI launch path, manual update-check feedback, and no Defender warning. Uninstall/reinstall, client pairing, streaming, and upgrade behavior still need fixture records. |
+| Installer execution | Partial | Manual VM smoke observed Nimbus default install path, visible Nimbus wording, service running with Nimbus description, Web UI launch path, manual update-check feedback, Artemis-on-Shield pairing, and no Defender warning. Uninstall/reinstall, streaming, and upgrade behavior still need fixture records. |
Artifacts:
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index 5808c6128d..8728fec1d1 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -65,7 +65,7 @@ so user-facing version surfaces no longer look like an unversioned build.
| --- | --- | --- | --- |
| Fresh install on clean Windows 11 x64 | Yes | Pending | Installer log, screenshots, service state |
| Launch Web UI after install | Yes | Pending | Local URL opens and login/setup path is reachable |
-| Pair with a compatible client | Yes | Pending | Artemis, Moonlight, or current compatible client can see the host |
+| Pair with a compatible client | Yes | Observed pass | Artemis on Shield TV paired with the Nimbus VM host |
| Start a short stream session | Yes | Pending | One local-network stream smoke, with hardware encoder noted |
| Uninstall | Yes | Pending | Add/Remove Programs entry removed and service stopped |
| Reinstall after uninstall | Yes | Pending | Reinstall completes without manual cleanup |
@@ -95,15 +95,19 @@ Observed so far:
| Uninstall confirmation modal | Observed pass | Modal copy correctly describes uninstall options and factory-reset behavior. |
| Uninstaller quick tips | Fixed, retest pending | An older candidate reused install/upgrade tips in uninstall mode. Fixed in `0af1f3b8`; retest with the current `0.0.0.44` candidate. |
| Manual tray update check | Observed pass | Maintainer confirmed the `Check for Update` tray action shows visible feedback in the VM. |
+| Compatible-client pairing | Observed pass | Artemis on Shield TV paired with the Nimbus VM host. |
+| Pairing notification target | Fixed, retest pending | Pairing toast now opens `/clients?sec=pair` so the Clients page scrolls directly to the Pair Client section. |
| Windows Defender prompt | Observed pass | Maintainer reported no Defender warning during the install smoke. |
Still blocking the alpha gate:
- Confirm the `0.0.0.44` uninstaller quick tips show uninstall-specific copy.
+- Confirm clicking the pairing notification scrolls directly to the Pair Client
+ section in the next candidate.
- Confirm uninstall removes or stops the service and removes the Add/Remove
Programs entry.
- Confirm reinstall after uninstall completes without manual cleanup.
-- Run at least one compatible-client pairing and short stream smoke.
+- Run a short stream smoke.
- Record upgrade behavior from Apollo and/or Vibepollo where practical.
## Evidence Commands
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index f374495b37..5ad23ce756 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -40,6 +40,8 @@ has wider testers.
- Added user-visible tray feedback for manual update checks so `Check for
Update` reports checking, already-running, no-release, up-to-date, or failure
status instead of only writing to logs.
+- Improved the incoming pairing notification target so it opens the Clients page
+ directly at the Pair Client section.
## Compatibility Notes
@@ -94,12 +96,12 @@ Partial manual VM observations from the previous candidate loop:
- The uninstaller quick-tip panel was fixed after VM feedback and still needs a
retest with the `0.0.0.44` candidate.
- Manual tray update-check feedback is visible in the VM.
+- Artemis on Shield TV can pair with the Nimbus VM host.
Pending before release:
- Retest the `0.0.0.44` uninstaller quick-tip copy.
- Uninstall and reinstall behavior.
-- Compatible-client pairing smoke.
- Short local-network stream smoke.
- Upgrade behavior from Apollo and/or Vibepollo where practical.
diff --git a/src/system_tray.cpp b/src/system_tray.cpp
index 68c0472c35..5d08ded9eb 100644
--- a/src/system_tray.cpp
+++ b/src/system_tray.cpp
@@ -535,7 +535,7 @@ namespace system_tray {
tray.notification_icon = TRAY_ICON_LOCKED;
tray.tooltip = PROJECT_NAME;
tray.notification_cb = []() {
- launch_ui("/clients");
+ launch_ui("/clients?sec=pair");
};
tray_update(&tray);
});
diff --git a/src_assets/common/assets/web/views/ClientManagementView.vue b/src_assets/common/assets/web/views/ClientManagementView.vue
index 8344719771..2816bebc9c 100644
--- a/src_assets/common/assets/web/views/ClientManagementView.vue
+++ b/src_assets/common/assets/web/views/ClientManagementView.vue
@@ -57,87 +57,91 @@
-
-
-
-
+
+
@@ -1084,6 +1088,7 @@ const { t } = useI18n();
const route = useRoute();
const message = useMessage();
const configStore = useConfigStore();
+const pairSectionRef = ref(null);
const apiTokensSectionRef = ref(null);
const globalPrefer10BitSdr = computed(() =>
toBool(configValue('prefer_10bit_sdr'), false),
@@ -2025,15 +2030,25 @@ function scrollToTokenSection(): void {
apiTokensSectionRef.value?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
+function scrollToPairSection(): void {
+ pairSectionRef.value?.scrollIntoView({ behavior: 'smooth', block: 'center' });
+}
+
+async function scrollToRequestedSection(section: unknown): Promise {
+ await nextTick();
+ if (section === 'tokens') {
+ scrollToTokenSection();
+ } else if (section === 'pair') {
+ scrollToPairSection();
+ }
+}
+
onMounted(async () => {
const auth = useAuthStore();
await configStore.fetchConfig().catch(() => {});
await auth.waitForAuthentication();
await refreshClients();
- if (route.query['sec'] === 'tokens') {
- await nextTick();
- scrollToTokenSection();
- }
+ await scrollToRequestedSection(route.query['sec']);
if (refreshIntervalId === null) {
refreshIntervalId = setInterval(() => {
void refreshClients();
@@ -2044,11 +2059,10 @@ onMounted(async () => {
watch(
() => route.query['sec'],
async (section) => {
- if (section !== 'tokens') {
+ if (section !== 'tokens' && section !== 'pair') {
return;
}
- await nextTick();
- scrollToTokenSection();
+ await scrollToRequestedSection(section);
},
);
From a777e40ab226a2da6e4690eda6ec5b4ad4305a95 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Thu, 21 May 2026 23:49:17 +1000
Subject: [PATCH 28/60] fix: retarget runtime display helper branding
---
docs/packaging-identity-plan.md | 1 +
docs/release-build-audit.md | 5 ++-
docs/windows-installer-fixture.md | 7 ++--
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 8 ++++-
src/state_storage.cpp | 4 +--
tools/display_settings_helper.cpp | 35 ++++++++++++++-----
6 files changed, 43 insertions(+), 17 deletions(-)
diff --git a/docs/packaging-identity-plan.md b/docs/packaging-identity-plan.md
index 5a31894b69..d339650116 100644
--- a/docs/packaging-identity-plan.md
+++ b/docs/packaging-identity-plan.md
@@ -114,6 +114,7 @@ Do not change these until there is a tested migration plan.
| Bootstrapper namespace | `VibepolloInstaller` | Split cosmetic UI naming from installer detection logic. |
| Bootstrapper output | `NimbusSetup.exe` | Changed in Phase C. Local Windows package build passed. |
| Start menu folder | `Nimbus` | Changed in Phase C. Validate shortcut cleanup tests. |
+| Display restore scheduled task | `NimbusDisplayRestore`; legacy `VibeshineDisplayRestore` is still deleted during cleanup | Active runtime task name changed after VM log feedback. Keep legacy deletion until upgrade/uninstall fixtures prove it is safe to remove. |
| Service names | `ApolloService`, `SunshineService`, `VibeshineService`, `sunshinesvc` | Preserve detection and cleanup paths until migration logic is explicit. |
| Config/state files | `sunshine.conf`, `sunshine_state.json` | Preserve for first branded release unless migration is built and tested. |
| WebRTC release scripts | Nimbus wording and fallback repo | Publishing remains manual and confirmation-gated. |
diff --git a/docs/release-build-audit.md b/docs/release-build-audit.md
index 20258ba07f..732b7c3a3b 100644
--- a/docs/release-build-audit.md
+++ b/docs/release-build-audit.md
@@ -278,7 +278,7 @@ Result:
| CPack WiX MSI | Pass | Initial sandbox run reached WiX but failed ICE validation because Windows Installer service access was unavailable; rerunning outside the sandbox with the same `WIX` path passed. |
| Bootstrapper | Pass | Final file metadata resolves to `Nimbus Installer`, `0.0.0.44`, `4f3411b2`, `Kuno Labs`. |
| Signing | Skipped | `SIGNPATH_API_TOKEN` was unset; output is unsigned. |
-| Installer execution | Partial | Manual VM smoke observed Nimbus default install path, visible Nimbus wording, service running with Nimbus description, Web UI launch path, manual update-check feedback, Artemis-on-Shield pairing, and no Defender warning. Uninstall/reinstall, streaming, and upgrade behavior still need fixture records. |
+| Installer execution | Partial | Manual VM smoke observed Nimbus default install path, visible Nimbus wording, service running with Nimbus description, Web UI launch path, manual update-check feedback, Artemis-on-Shield pairing, Artemis streaming/disconnect, and no Defender warning. Uninstall/reinstall and upgrade behavior still need fixture records. |
Artifacts:
@@ -289,8 +289,7 @@ Artifacts:
Current caveat: these artifacts are newer and better branded than the earlier
`82fa5cdd` validation artifacts, but they are still local validation artifacts
-until the remaining VM uninstall, reinstall, pairing, stream, and upgrade
-evidence is recorded.
+until the remaining VM uninstall, reinstall, and upgrade evidence is recorded.
## Required Secrets Before Release CI
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index 8728fec1d1..a994264b28 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -66,7 +66,7 @@ so user-facing version surfaces no longer look like an unversioned build.
| Fresh install on clean Windows 11 x64 | Yes | Pending | Installer log, screenshots, service state |
| Launch Web UI after install | Yes | Pending | Local URL opens and login/setup path is reachable |
| Pair with a compatible client | Yes | Observed pass | Artemis on Shield TV paired with the Nimbus VM host |
-| Start a short stream session | Yes | Pending | One local-network stream smoke, with hardware encoder noted |
+| Start a short stream session | Yes | Observed pass | Artemis on Shield TV streamed from the Nimbus VM host and disconnected cleanly |
| Uninstall | Yes | Pending | Add/Remove Programs entry removed and service stopped |
| Reinstall after uninstall | Yes | Pending | Reinstall completes without manual cleanup |
| Upgrade from Vibepollo | Strongly recommended | Pending | Config, credentials, and paired-client state checked |
@@ -96,7 +96,9 @@ Observed so far:
| Uninstaller quick tips | Fixed, retest pending | An older candidate reused install/upgrade tips in uninstall mode. Fixed in `0af1f3b8`; retest with the current `0.0.0.44` candidate. |
| Manual tray update check | Observed pass | Maintainer confirmed the `Check for Update` tray action shows visible feedback in the VM. |
| Compatible-client pairing | Observed pass | Artemis on Shield TV paired with the Nimbus VM host. |
+| Compatible-client stream smoke | Observed pass | Artemis on Shield TV streamed from the Nimbus VM host and disconnected cleanly; no issues observed so far. |
| Pairing notification target | Fixed, retest pending | Pairing toast now opens `/clients?sec=pair` so the Clients page scrolls directly to the Pair Client section. |
+| Runtime log branding | Fixed, retest pending | Fixture logs still showed `VibeshineDisplayRestore` and `vibeshine state`; active runtime logs now use Nimbus wording while legacy cleanup still removes old Vibeshine tasks. |
| Windows Defender prompt | Observed pass | Maintainer reported no Defender warning during the install smoke. |
Still blocking the alpha gate:
@@ -104,10 +106,11 @@ Still blocking the alpha gate:
- Confirm the `0.0.0.44` uninstaller quick tips show uninstall-specific copy.
- Confirm clicking the pairing notification scrolls directly to the Pair Client
section in the next candidate.
+- Confirm the next candidate logs `NimbusDisplayRestore` and `Nimbus state file`
+ instead of new runtime `Vibeshine` task/state messages.
- Confirm uninstall removes or stops the service and removes the Add/Remove
Programs entry.
- Confirm reinstall after uninstall completes without manual cleanup.
-- Run a short stream smoke.
- Record upgrade behavior from Apollo and/or Vibepollo where practical.
## Evidence Commands
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index 5ad23ce756..0ce9fc434b 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -42,6 +42,9 @@ has wider testers.
status instead of only writing to logs.
- Improved the incoming pairing notification target so it opens the Clients page
directly at the Pair Client section.
+- Retargeted the active Windows display-restore scheduled task and related
+ state-file log messages to Nimbus wording while preserving legacy Vibeshine
+ cleanup during uninstall/restore task deletion.
## Compatibility Notes
@@ -97,12 +100,15 @@ Partial manual VM observations from the previous candidate loop:
retest with the `0.0.0.44` candidate.
- Manual tray update-check feedback is visible in the VM.
- Artemis on Shield TV can pair with the Nimbus VM host.
+- Artemis on Shield TV can stream from the Nimbus VM host and disconnect
+ cleanly in the current local-network smoke test.
Pending before release:
- Retest the `0.0.0.44` uninstaller quick-tip copy.
- Uninstall and reinstall behavior.
-- Short local-network stream smoke.
+- Retest the pairing notification deep link and runtime log-branding cleanup in
+ the next candidate build.
- Upgrade behavior from Apollo and/or Vibepollo where practical.
## Known Issues And Caveats
diff --git a/src/state_storage.cpp b/src/state_storage.cpp
index 2d5fab267d..0c244f318a 100644
--- a/src/state_storage.cpp
+++ b/src/state_storage.cpp
@@ -405,7 +405,7 @@ namespace statefile {
migrate_recent_state_keys();
const auto &path_str = vibeshine_state_path();
if (path_str.empty()) {
- BOOST_LOG(warning) << "statefile: cannot save snapshot exclusions - vibeshine state path is empty";
+ BOOST_LOG(warning) << "statefile: cannot save snapshot exclusions - Nimbus state file path is empty";
return;
}
@@ -434,7 +434,7 @@ namespace statefile {
BOOST_LOG(error) << "statefile: failed to write "sv << path.string() << ": "sv << e.what();
return;
}
- BOOST_LOG(info) << "statefile: persisted " << devices.size() << " snapshot exclusion device(s) to vibeshine state";
+ BOOST_LOG(info) << "statefile: persisted " << devices.size() << " snapshot exclusion device(s) to Nimbus state file";
}
std::vector load_snapshot_exclude_devices() {
diff --git a/tools/display_settings_helper.cpp b/tools/display_settings_helper.cpp
index cefcc26a93..e4719a191a 100644
--- a/tools/display_settings_helper.cpp
+++ b/tools/display_settings_helper.cpp
@@ -115,9 +115,25 @@ namespace {
}
std::wstring build_restore_task_name(const std::wstring &username) {
+ (void) username;
+ return L"NimbusDisplayRestore";
+ }
+
+ std::wstring build_legacy_vibeshine_restore_task_name(const std::wstring &username) {
+ (void) username;
return L"VibeshineDisplayRestore";
}
+ void add_unique_task_name(std::vector &task_names, std::wstring task_name) {
+ if (task_name.empty()) {
+ return;
+ }
+ if (std::find(task_names.begin(), task_names.end(), task_name) != task_names.end()) {
+ return;
+ }
+ task_names.push_back(std::move(task_name));
+ }
+
// Trigger a more robust Explorer/shell refresh so that desktop/taskbar icons
// and other shell-controlled UI elements pick up DPI/metrics changes that
// can occur after monitor topology/primary swaps. Avoids wrong-sized icons
@@ -4134,8 +4150,6 @@ namespace {
}
bool create_restore_scheduled_task() {
- BOOST_LOG(info) << "Attempting to create scheduled task 'VibeshineDisplayRestore'...";
-
const DWORD active_session_id = WTSGetActiveConsoleSessionId();
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
@@ -4182,7 +4196,7 @@ namespace {
IRegistrationInfo *reg_info = nullptr;
hr = task->get_RegistrationInfo(®_info);
if (SUCCEEDED(hr)) {
- reg_info->put_Author(_bstr_t(L"Sunshine Display Helper"));
+ reg_info->put_Author(_bstr_t(L"Nimbus Display Helper"));
reg_info->put_Description(_bstr_t(L"Automatically restores display settings after reboot"));
reg_info->Release();
}
@@ -4241,6 +4255,7 @@ namespace {
}
const std::wstring task_name = build_restore_task_name(has_username ? username : std::wstring {});
+ BOOST_LOG(info) << "Attempting to create scheduled task '" << std::string(task_name.begin(), task_name.end()) << "'...";
wchar_t exe_path[MAX_PATH];
if (!GetModuleFileNameW(nullptr, exe_path, MAX_PATH)) {
@@ -4279,7 +4294,7 @@ namespace {
hr = trigger->QueryInterface(IID_ILogonTrigger, (void **) &logon_trigger);
trigger->Release();
if (SUCCEEDED(hr)) {
- logon_trigger->put_Id(_bstr_t(L"SunshineDisplayHelperLogonTrigger"));
+ logon_trigger->put_Id(_bstr_t(L"NimbusDisplayHelperLogonTrigger"));
logon_trigger->put_Enabled(VARIANT_TRUE);
if (has_username) {
logon_trigger->put_UserId(_bstr_t(username.c_str()));
@@ -4424,11 +4439,13 @@ namespace {
}
std::vector task_names;
- task_names.push_back(build_restore_task_name({}));
+ add_unique_task_name(task_names, build_restore_task_name({}));
+ add_unique_task_name(task_names, build_legacy_vibeshine_restore_task_name({}));
if (!username.empty()) {
if (_wcsicmp(username.c_str(), L"SYSTEM") != 0 && _wcsicmp(username.c_str(), L"NT AUTHORITY\\SYSTEM") != 0) {
- task_names.push_back(build_restore_task_name(username));
+ add_unique_task_name(task_names, build_restore_task_name(username));
+ add_unique_task_name(task_names, build_legacy_vibeshine_restore_task_name(username));
}
}
@@ -4600,7 +4617,7 @@ namespace {
}
}
} catch (const std::exception &e) {
- BOOST_LOG(warning) << "Failed to parse vibeshine_state.json for snapshot exclusions: " << e.what();
+ BOOST_LOG(warning) << "Failed to parse Nimbus state file for snapshot exclusions: " << e.what();
} catch (...) {
}
return false;
@@ -4975,7 +4992,7 @@ int main(int argc, char *argv[]) {
for (const auto &root : search_roots) {
const auto vibeshine_state_file = root / L"vibeshine_state.json";
if (load_vibeshine_snapshot_exclusions(vibeshine_state_file, persisted)) {
- BOOST_LOG(info) << "Loaded snapshot exclusions from vibeshine_state.json (" << persisted.size()
+ BOOST_LOG(info) << "Loaded snapshot exclusions from Nimbus state file (" << persisted.size()
<< ") at " << vibeshine_state_file.string();
state.controller.set_snapshot_exclusions(persisted);
break;
@@ -5050,7 +5067,7 @@ int main(int argc, char *argv[]) {
for (const auto &root : search_roots) {
const auto vibeshine_state_file = root / L"vibeshine_state.json";
if (load_vibeshine_snapshot_exclusions(vibeshine_state_file, persisted)) {
- BOOST_LOG(info) << "Loaded snapshot exclusions from vibeshine_state.json (" << persisted.size()
+ BOOST_LOG(info) << "Loaded snapshot exclusions from Nimbus state file (" << persisted.size()
<< ") at " << vibeshine_state_file.string();
state.controller.set_snapshot_exclusions(persisted);
break;
From 4b9379e49a4f1f372658f529a2ea9e4980b84599 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Fri, 22 May 2026 00:09:51 +1000
Subject: [PATCH 29/60] fix: clean visible inherited naming
---
docs/naming-identity-audit.md | 108 ++++++++++++++++++
docs/packaging-identity-plan.md | 2 +
docs/windows-installer-fixture.md | 3 +
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 5 +
.../assets/web/configs/tabs/Capture.vue | 4 +-
.../common/assets/web/configs/tabs/Files.vue | 8 +-
.../assets/web/configs/tabs/General.vue | 2 +-
.../assets/web/configs/tabs/Network.vue | 6 +-
.../common/assets/web/package-lock.json | 4 +-
src_assets/common/assets/web/package.json | 2 +-
.../assets/web/public/assets/locale/en.json | 40 +++----
.../web/public/assets/locale/en_GB.json | 32 +++---
.../web/public/assets/locale/en_US.json | 32 +++---
13 files changed, 183 insertions(+), 65 deletions(-)
create mode 100644 docs/naming-identity-audit.md
diff --git a/docs/naming-identity-audit.md b/docs/naming-identity-audit.md
new file mode 100644
index 0000000000..1eaafd3071
--- /dev/null
+++ b/docs/naming-identity-audit.md
@@ -0,0 +1,108 @@
+# Nimbus Naming Identity Audit
+
+Snapshot date: 2026-05-21
+
+This audit tracks inherited names from Vibepollo, Vibeshine, Apollo, Sunshine,
+Moonlight, and Artemis. It separates visible Nimbus polish from compatibility
+anchors that need a migration plan.
+
+## Naming Policy
+
+```mermaid
+flowchart TD
+ A["Inherited name found"] --> B{"Visible to users?"}
+ B -- "yes" --> C{"Protocol or factual compatibility?"}
+ C -- "yes" --> D["Use neutral wording or Moonlight-compatible"]
+ C -- "no" --> E["Rename to Nimbus"]
+ B -- "no" --> F{"Runtime, config, upgrade, or external API anchor?"}
+ F -- "yes" --> G["Defer until migration fixture exists"]
+ F -- "no" --> H["Rename when nearby code is touched"]
+
+ I["Lucent"] --> J["Use for our future client fork"]
+ J --> K["Do not present Lucent as available until the fork exists"]
+```
+
+Guidance:
+
+- `Nimbus` is the host product name.
+- `Lucent` is reserved for the planned client project.
+- Use `compatible client` in settings and support text when the exact client
+ does not matter.
+- Use `Moonlight-compatible client` where protocol compatibility or discoverable
+ ecosystem wording matters.
+- Use `Artemis` only for factual references, fixture evidence, or links to the
+ current Artemis client.
+- Do not rename runtime keys, service names, executable names, config filenames,
+ upgrade codes, app ids, or protocol classes without a dedicated migration
+ fixture.
+
+## Current Scan Summary
+
+Targeted scan commands:
+
+```powershell
+rg -n "Vibeshine|Vibepollo|Apollo|Sunshine|Moonlight|Artemis|Lucent" src_assets\common\assets\web
+rg -n "Vibeshine|Vibepollo|Apollo|Sunshine|Moonlight|Artemis|Lucent" src tools packaging cmake scripts docs release_notes .github tests
+rg -l "sunshine|Sunshine|Vibeshine|Vibepollo|Apollo|Moonlight|Artemis|Lucent" .
+```
+
+Repo-wide file-match counts on this snapshot:
+
+| Term | Files |
+| --- | ---: |
+| `sunshine` | 181 |
+| `Sunshine` | 150 |
+| `Vibepollo` | 53 |
+| `Moonlight` | 49 |
+| `Apollo` | 37 |
+| `Vibeshine` | 21 |
+| `Artemis` | 9 |
+| `Lucent` | 13 |
+
+Top matched folders: `src` (82 files), `src_assets` (57), `packaging` (26),
+`docs` (25), `cmake` (18), and `tests` (17).
+
+High-signal findings:
+
+| Area | Current stance | Notes |
+| --- | --- | --- |
+| English Web UI labels and descriptions | Rename or neutralize now | Current pass removed screenshot-level `Vibeshine` placeholders and most direct `Moonlight` instructions. |
+| Web UI package manifest | Rename now | `src_assets/common/assets/web` now identifies as `nimbus-web` in package metadata and build output. |
+| Non-English locale files | Defer as localization work | Many translations still say Vibepollo or Moonlight. Mechanical replacement would create bad translations. |
+| `sunshine_name`, `vibeshine_file_state` config keys | Preserve | User-facing labels can say Nimbus, but changing keys affects config compatibility. |
+| `sunshine_state.json`, `vibeshine_state.json`, `sunshine.log` defaults | Preserve for alpha | UI placeholders should not advertise inherited filenames, but runtime filename migration needs backup and upgrade tests. |
+| `ApolloService` | Preserve for alpha | Visible service description is Nimbus Service; internal service name affects upgrade and uninstall behavior. |
+| `SunshineVersion`, `sunshine_version.ts` | Defer | Internal comparator name, not visible UI. Rename later with tests. |
+| `Moonlight-compatible clients` | Keep selectively | Accurate compatibility wording while Lucent does not exist. |
+| `Artemis` in fixture notes | Keep | Factual test evidence from Shield TV pairing and stream smoke. |
+| `Artemis` in client-link UI | Defer | It points to the current Artemis/Moonlight Android ecosystem. Replace with Lucent only when Lucent exists. |
+| Historical release notes | Preserve | Upstream release-note files intentionally describe Vibepollo history. |
+| Linux packaging ids and appstream | Defer | These are platform package identity surfaces and need their own Linux fixture. |
+
+## Current Visible Cleanup
+
+Completed in this pass:
+
+- General settings host-name placeholder now says `Nimbus`.
+- File settings placeholders now use neutral `Automatic` text instead of
+ inherited filenames.
+- The Web UI package manifest now uses `nimbus-web` so maintainer build output
+ no longer prints `sunshine`.
+- Lossless Scaling status and browse messages now say Nimbus.
+- English locale copy now uses `compatible client` for certificate, private key,
+ pairing, bitrate, input, and troubleshooting guidance.
+- English video setting descriptions now say Nimbus instead of inherited
+ Sunshine wording.
+- The Web UI still says `Moonlight-compatible clients` in the product
+ description because that is accurate for the first alpha.
+
+## Deferred Migration Lanes
+
+| Lane | Scope | Minimum validation |
+| --- | --- | --- |
+| Runtime config filenames | `sunshine_state.json`, `vibeshine_state.json`, `sunshine.log` | Backup, migration, rollback, upgrade from Apollo/Vibepollo, uninstall/reinstall. |
+| Service identity | `ApolloService`, `sunshinesvc`, related scripts | Upgrade/uninstall fixture plus Windows service recovery tests. |
+| Executable/helper names | `sunshine.exe`, `sunshine_display_helper.exe`, `sunshine_wgc_capture.exe` | Installer payload, service launch, crash/log collection, firewall, shortcuts. |
+| Client identity | Artemis/Moonlight links and copy | Create Lucent fork or public repo first, then update links and client docs. |
+| Translations | Non-English locale files | Human or reviewed machine translation pass; avoid blind replacement. |
+| Linux platform identity | FQDN, desktop files, Flatpak/AppImage metadata | Linux package build and install smoke. |
diff --git a/docs/packaging-identity-plan.md b/docs/packaging-identity-plan.md
index d339650116..44fc2cbd0c 100644
--- a/docs/packaging-identity-plan.md
+++ b/docs/packaging-identity-plan.md
@@ -6,6 +6,8 @@ This plan separates public Nimbus branding from runtime identifiers that affect
installs, upgrades, shortcuts, services, config paths, and platform packages.
The fork inherited names from Vibepollo, Apollo, Sunshine, and Vibeshine. Some
of those names are user-facing strings. Others are compatibility anchors.
+See `docs/naming-identity-audit.md` for the current inherited-name scan and
+Lucent client naming policy.
Do not rename every inherited identifier in one broad sweep. Each package or
runtime identity change should have a migration note, a rollback expectation,
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index a994264b28..e4a01e10a9 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -99,6 +99,7 @@ Observed so far:
| Compatible-client stream smoke | Observed pass | Artemis on Shield TV streamed from the Nimbus VM host and disconnected cleanly; no issues observed so far. |
| Pairing notification target | Fixed, retest pending | Pairing toast now opens `/clients?sec=pair` so the Clients page scrolls directly to the Pair Client section. |
| Runtime log branding | Fixed, retest pending | Fixture logs still showed `VibeshineDisplayRestore` and `vibeshine state`; active runtime logs now use Nimbus wording while legacy cleanup still removes old Vibeshine tasks. |
+| Settings naming polish | Fixed, retest pending | General and Files settings no longer show `Vibeshine`, `sunshine_state.json`, `sunshine.log`, or `vibeshine_state.json` as low-risk visible placeholders. |
| Windows Defender prompt | Observed pass | Maintainer reported no Defender warning during the install smoke. |
Still blocking the alpha gate:
@@ -108,6 +109,8 @@ Still blocking the alpha gate:
section in the next candidate.
- Confirm the next candidate logs `NimbusDisplayRestore` and `Nimbus state file`
instead of new runtime `Vibeshine` task/state messages.
+- Confirm the General and Files settings pages do not show inherited host names
+ or filenames as visible placeholder text.
- Confirm uninstall removes or stops the service and removes the Add/Remove
Programs entry.
- Confirm reinstall after uninstall completes without manual cleanup.
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index 0ce9fc434b..2e30c82a73 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -45,6 +45,9 @@ has wider testers.
- Retargeted the active Windows display-restore scheduled task and related
state-file log messages to Nimbus wording while preserving legacy Vibeshine
cleanup during uninstall/restore task deletion.
+- Added a naming identity audit for inherited Sunshine, Vibeshine, Moonlight,
+ Artemis, Apollo, and Vibepollo surfaces, then cleaned low-risk visible Web UI
+ settings copy, placeholders, and Web UI package metadata.
## Compatibility Notes
@@ -109,6 +112,8 @@ Pending before release:
- Uninstall and reinstall behavior.
- Retest the pairing notification deep link and runtime log-branding cleanup in
the next candidate build.
+- Retest the General and Files settings pages for inherited visible names in
+ the next candidate build.
- Upgrade behavior from Apollo and/or Vibepollo where practical.
## Known Issues And Caveats
diff --git a/src_assets/common/assets/web/configs/tabs/Capture.vue b/src_assets/common/assets/web/configs/tabs/Capture.vue
index 8a4c82f8ca..8e4d3ad3e1 100644
--- a/src_assets/common/assets/web/configs/tabs/Capture.vue
+++ b/src_assets/common/assets/web/configs/tabs/Capture.vue
@@ -204,7 +204,7 @@ const losslessStatusHint = computed(() => {
if (losslessDetected.value) {
return `Lossless Scaling is detected and will be launched when selected as the primary frame generation in any application.`;
}
- return 'Vibeshine could not find Lossless Scaling. Scan for an installation or provide the executable path below.';
+ return 'Nimbus could not find Lossless Scaling. Scan for an installation or provide the executable path below.';
});
async function refreshLosslessStatus() {
@@ -475,7 +475,7 @@ const shouldShowSoftware = computed(() => showAll() || props.currentTab === 'sw'
>
- Vibeshine searched common Steam and program directories but could not locate
+ Nimbus searched common Steam and program directories but could not locate
LosslessScaling.exe. Install Lossless Scaling from Steam or set the full path manually.
{{ $t('config.port_http_port_note') }}
diff --git a/src_assets/common/assets/web/package-lock.json b/src_assets/common/assets/web/package-lock.json
index 8a4b4b0cb6..be1e9ba946 100644
--- a/src_assets/common/assets/web/package-lock.json
+++ b/src_assets/common/assets/web/package-lock.json
@@ -1,11 +1,11 @@
{
- "name": "sunshine",
+ "name": "nimbus-web",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "sunshine",
+ "name": "nimbus-web",
"version": "0.0.0",
"dependencies": {
"@fortawesome/fontawesome-free": "6.5.2",
diff --git a/src_assets/common/assets/web/package.json b/src_assets/common/assets/web/package.json
index e860baa2e1..d488bcad2e 100644
--- a/src_assets/common/assets/web/package.json
+++ b/src_assets/common/assets/web/package.json
@@ -1,5 +1,5 @@
{
- "name": "sunshine",
+ "name": "nimbus-web",
"version": "0.0.0",
"scripts": {
"build": "vite build --mode prod",
diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json
index 77a6058a10..b9045e384c 100644
--- a/src_assets/common/assets/web/public/assets/locale/en.json
+++ b/src_assets/common/assets/web/public/assets/locale/en.json
@@ -42,7 +42,7 @@
"add_cmds": "Add Commands",
"add_new": "Add New",
"app_name": "Application Name",
- "app_name_desc": "Application Name, as shown on Moonlight",
+ "app_name_desc": "Application name as shown in compatible clients",
"applications_desc": "Applications are refreshed only when Client is restarted",
"applications_title": "Applications",
"auto_detach": "Continue streaming if the application exits quickly",
@@ -195,7 +195,7 @@
"capture_ddx_legacy": "Desktop Duplication API (legacy)",
"capture_autodetect_legacy": "Automatic (legacy fallback)",
"cert": "Certificate",
- "cert_desc": "The certificate used for the web UI and Moonlight client pairing. For best compatibility, this should have an RSA-2048 public key.",
+ "cert_desc": "The certificate used for the web UI and compatible client pairing. For best compatibility, this should have an RSA-2048 public key.",
"channels": "Maximum Connected Clients",
"channels_desc_1": "Nimbus can allow a single streaming session to be shared with multiple clients simultaneously.",
"channels_desc_2": "Some hardware encoders may have limitations that reduce performance with multiple streams.",
@@ -390,7 +390,7 @@
"hevc_mode_3": "Nimbus will advertise support for HEVC Main and Main10 (HDR) profiles",
"hevc_mode_desc": "Allows the client to request HEVC Main or HEVC Main10 video streams. HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.",
"high_resolution_scrolling": "High Resolution Scrolling Support",
- "high_resolution_scrolling_desc": "When enabled, Nimbus will pass through high resolution scroll events from Moonlight clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
+ "high_resolution_scrolling_desc": "When enabled, Nimbus will pass through high resolution scroll events from compatible clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
"install_steam_audio_drivers": "Install Steam Audio Drivers",
"install_steam_audio_drivers_desc": "If Steam is installed, this will automatically install the Steam Streaming Speakers driver to support 5.1/7.1 surround sound and muting host audio.",
"key_repeat_delay": "Key Repeat Delay",
@@ -398,7 +398,7 @@
"key_repeat_frequency": "Key Repeat Frequency",
"key_repeat_frequency_desc": "How often keys repeat every second. This configurable option supports decimals.",
"key_rightalt_to_key_win": "Map Right Alt key to Windows key",
- "key_rightalt_to_key_win_desc": "It may be possible that you cannot send the Windows Key from Moonlight directly. In those cases it may be useful to make Nimbus think the Right Alt key is the Windows key",
+ "key_rightalt_to_key_win_desc": "Some clients cannot send the Windows key directly. In those cases it may be useful to make Nimbus think the Right Alt key is the Windows key",
"keybindings": "Keybindings",
"keyboard": "Enable Keyboard Input",
"keyboard_desc": "Allows guests to control the host system with the keyboard",
@@ -411,7 +411,7 @@
"log_path": "Logfile Path",
"log_path_desc": "The file where the current logs of Nimbus are stored.",
"max_bitrate": "Maximum Bitrate",
- "max_bitrate_desc": "The maximum bitrate (in Kbps) that Nimbus will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.",
+ "max_bitrate_desc": "The maximum bitrate (in Kbps) that Nimbus will encode the stream at. If set to 0, it will always use the bitrate requested by the client.",
"minimum_fps_target": "Minimum FPS Target",
"minimum_fps_target_desc": "The lowest effective FPS a stream can reach. A value of 0 is treated as roughly half of the stream's FPS. A setting of 20 is recommended if you stream 24 or 30fps content.",
"session_token_ttl_seconds": "Web UI Session Timeout (seconds)",
@@ -441,7 +441,7 @@
"mouse": "Enable Mouse Input",
"mouse_desc": "Allows guests to control the host system with the mouse",
"native_pen_touch": "Native Pen/Touch Support",
- "native_pen_touch_desc": "When enabled, Nimbus will pass through native pen/touch events from Moonlight clients. This can be useful to disable for older applications without native pen/touch support.",
+ "native_pen_touch_desc": "When enabled, Nimbus will pass through native pen/touch events from compatible clients. This can be useful to disable for older applications without native pen/touch support.",
"notify_pre_releases": "PreRelease Notifications",
"notify_pre_releases_desc": "Whether to be notified of new pre-release versions of Nimbus",
"update_check_interval": "Update Check Interval (seconds)",
@@ -451,7 +451,7 @@
"nvenc_latency_over_power": "Prefer lower encoding latency over power savings",
"nvenc_latency_over_power_desc": "Nimbus requests maximum GPU clock speed while streaming to reduce encoding latency. Disabling it is not recommended since this can lead to significantly increased encoding latency.",
"nvenc_opengl_vulkan_on_dxgi": "Present OpenGL/Vulkan on top of DXGI",
- "nvenc_opengl_vulkan_on_dxgi_desc": "Nimbus can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted on sunshine program exit.",
+ "nvenc_opengl_vulkan_on_dxgi_desc": "Nimbus can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted when Nimbus exits.",
"nvenc_preset": "Performance preset",
"nvenc_preset_1": "(fastest, default)",
"nvenc_preset_4": "(balanced quality)",
@@ -470,7 +470,7 @@
"nvenc_twopass_full_res": "Full resolution (slower)",
"nvenc_twopass_quarter_res": "Quarter resolution (faster, default)",
"nvenc_vbv_increase": "Single-frame VBV/HRD percentage increase",
- "nvenc_vbv_increase_desc": "By default sunshine uses single-frame VBV/HRD, which means any encoded video frame size is not expected to exceed requested bitrate divided by requested frame rate. Relaxing this restriction can be beneficial and act as low-latency variable bitrate, but may also lead to packet loss if the network doesn't have buffer headroom to handle bitrate spikes. Maximum accepted value is 400, which corresponds to 5x increased encoded video frame upper size limit.",
+ "nvenc_vbv_increase_desc": "By default Nimbus uses single-frame VBV/HRD, which means any encoded video frame size is not expected to exceed requested bitrate divided by requested frame rate. Relaxing this restriction can be beneficial and act as low-latency variable bitrate, but may also lead to packet loss if the network doesn't have buffer headroom to handle bitrate spikes. Maximum accepted value is 400, which corresponds to 5x increased encoded video frame upper size limit.",
"origin_web_ui_allowed": "Origin Web UI Allowed",
"origin_web_ui_allowed_desc": "The origin of the remote endpoint address that is not denied access to Web UI",
"origin_web_ui_allowed_lan": "Only those in LAN may access Web UI",
@@ -485,12 +485,12 @@
"video_max_batch_size_kb": "Max Video Batch Size",
"video_max_batch_size_kb_desc": "Maximum size in KiB for each outgoing video send batch. The default is 64 KiB. Lower values can improve stream stability on cheaper switches, routers, and Wi-Fi gear, at the cost of less than 1 ms of extra host-side delay.",
"pkey": "Private Key",
- "pkey_desc": "The private key used for the web UI and Moonlight client pairing. For best compatibility, this should be an RSA-2048 private key.",
+ "pkey_desc": "The private key used for the web UI and compatible client pairing. For best compatibility, this should be an RSA-2048 private key.",
"port": "Port",
"port_alert_1": "Nimbus cannot use ports below 1024!",
"port_alert_2": "Ports above 65535 are not available!",
"port_desc": "Set the family of ports used by Nimbus",
- "port_http_port_note": "Use this port to connect with Moonlight.",
+ "port_http_port_note": "Use this port to connect from compatible clients.",
"port_note": "Note",
"port_port": "Port",
"port_protocol": "Protocol",
@@ -523,7 +523,7 @@
"stream_audio": "Stream Audio",
"stream_audio_desc": "Whether to stream audio or not. Disabling this can be useful for streaming headless displays as second monitors.",
"sunshine_name": "Nimbus Name",
- "sunshine_name_desc": "The name displayed by Moonlight. If not specified, the PC's hostname is used",
+ "sunshine_name_desc": "The host name shown in compatible clients. If not specified, the PC's hostname is used",
"sw_preset": "SW Presets",
"sw_preset_desc": "Optimize the trade-off between encoding speed (encoded frames per second) and compression efficiency (quality per bit in the bitstream). Defaults to superfast.",
"sw_preset_fast": "fast",
@@ -588,7 +588,7 @@
"server_cmd": "Server Commands",
"server_cmd_desc": "Configure a list of commands to be executed when called from client during streaming.",
"enable_pairing": "Enable Pairing",
- "enable_pairing_desc": "Enable pairing for the Moonlight client. This allows the client to authenticate with the host and establish a secure connection.",
+ "enable_pairing_desc": "Enable pairing for compatible clients. This allows the client to authenticate with the host and establish a secure connection.",
"enable_discovery": "Enable Auto Discovery",
"enable_discovery_desc": "When disabled, you'll need to manually enter host IP on the client to pair.",
"enable_input_only_mode": "Enable Input Only Mode",
@@ -610,7 +610,7 @@
"ignore_encoder_probe_failure": "Ignore Encoder Probe Failure",
"ignore_encoder_probe_failure_desc": "Allow streaming to continue even if probing for encoders fails. This may result in streaming failure if no encoder is available.",
"legacy_ordering": "App ordering for legacy clients",
- "legacy_ordering_desc": "Enable ordering support workaround for legacy clients. Can cause issues with clients or scripts that can't handle UTF8 correctly. Artemis clients support this by default."
+ "legacy_ordering_desc": "Enable ordering support workaround for legacy clients. Can cause issues with clients or scripts that can't handle UTF8 correctly. Modern compatible clients support this by default."
},
"index": {
"description": "Nimbus is a self-hosted game stream host for Moonlight-compatible clients.",
@@ -703,7 +703,7 @@
"nav": "Clients",
"title": "Client Management",
"pair_title": "Pair Client",
- "pair_desc": "Enter the 4-digit PIN shown in Moonlight along with a friendly device name to pair this client.",
+ "pair_desc": "Enter the 4-digit PIN shown in the client along with a friendly device name to pair this client.",
"existing_title": "Paired Clients",
"connected": "Connected",
"last_seen": "Last seen: {time}",
@@ -740,9 +740,9 @@
"editing_title": "Editing {name}",
"empty_filtered": "No clients match these filters.",
"empty_filtered_desc": "Clear the search or status filter to see every paired client again.",
- "empty_pair_hint": "Pair a Moonlight device above to manage client-specific display, HDR, and stream settings.",
+ "empty_pair_hint": "Pair a compatible device above to manage client-specific display, HDR, and stream settings.",
"filters_clear": "Clear filters",
- "hero_desc": "Manage paired Moonlight devices, pairing access, display routing, HDR profiles, and per-client stream overrides.",
+ "hero_desc": "Manage paired compatible devices, pairing access, display routing, HDR profiles, and per-client stream overrides.",
"last_updated": "Updated {time}",
"last_updated_never": "Not refreshed yet",
"loading": "Loading clients...",
@@ -892,7 +892,7 @@
"tip_resolution": "Stream resolution (width × height in pixels) negotiated with the client.",
"tip_fps": "Target frames-per-second the encoder is asked to produce.",
"tip_bitrate": "Target video bitrate in megabits per second (Mbps).",
- "tip_bitrate_dual": "Top: the bandwidth budget you set on the client (e.g. 40 Mbps in Moonlight). Bottom (encode): what's left for the video encoder after Nimbus subtracts FEC error-correction (~20% by default), audio (~192 kbps), and ~500 kbps of control overhead. This is normal and expected.",
+ "tip_bitrate_dual": "Top: the bandwidth budget you set on the client (e.g. 40 Mbps). Bottom (encode): what's left for the video encoder after Nimbus subtracts FEC error-correction (~20% by default), audio (~192 kbps), and ~500 kbps of control overhead. This is normal and expected.",
"tip_codec": "Video codec used for this session (H.264, HEVC, or AV1).",
"tip_audio_channels": "Number of audio channels (e.g. 2ch = stereo, 6ch = 5.1 surround).",
"tip_encode_latency": "Time the GPU/CPU spent encoding the latest frame. <8ms is excellent, 8–16ms acceptable, >16ms means encoder can't keep up.",
@@ -914,7 +914,7 @@
"tip_profile": "Video codec profile/level negotiated with the client.",
"tip_last_video": "Time since the last video packet was sent. Should be < 100ms while streaming.",
"tip_last_audio": "Time since the last audio packet was sent. Should be < 100ms while streaming.",
- "tip_history_client": "Friendly name of the client app (e.g. Moonlight on a specific device).",
+ "tip_history_client": "Friendly name of the client app on a specific device.",
"tip_history_device": "Hardware/OS device name reported by the client.",
"tip_history_app": "The Nimbus application that was launched for this session.",
"tip_history_duration": "How long the streaming session lasted from start to disconnect.",
@@ -1066,7 +1066,7 @@
"display_mode_override": "Display mode override",
"display_mode_override_desc": "Force Nimbus to use this resolution and refresh rate for this client (format: 1920x1080x60). Leave blank to use the client's request.",
"pair_failure": "Pairing Failed: Check if the PIN is typed correctly",
- "pair_success": "Success! Please check Moonlight to continue",
+ "pair_success": "Success! Please check the client to continue",
"pin_pairing": "PIN Pairing",
"send": "Pair",
"warning_msg": "Make sure you have access to the client you are pairing with. This software can give total control to your computer, so be careful!"
@@ -1119,7 +1119,7 @@
"dd_golden_delete_error": "Failed to delete golden display snapshot.",
"dd_golden_refresh": "Check Again",
"force_close": "Force Close",
- "force_close_desc": "If Moonlight complains about an app currently running, force closing the app should fix the issue.",
+ "force_close_desc": "If a client reports that an app is already running, force closing the app should fix the issue.",
"force_close_error": "Error while closing Application",
"force_close_success": "Application Closed Successfully!",
"logs": "Logs",
diff --git a/src_assets/common/assets/web/public/assets/locale/en_GB.json b/src_assets/common/assets/web/public/assets/locale/en_GB.json
index 7802ef2074..9deb095259 100644
--- a/src_assets/common/assets/web/public/assets/locale/en_GB.json
+++ b/src_assets/common/assets/web/public/assets/locale/en_GB.json
@@ -41,7 +41,7 @@
"add_cmds": "Add Commands",
"add_new": "Add New",
"app_name": "Application Name",
- "app_name_desc": "Application Name, as shown on Moonlight",
+ "app_name_desc": "Application name as shown in compatible clients",
"applications_desc": "Applications are refreshed only when Client is restarted",
"applications_title": "Applications",
"auto_detach": "Continue streaming if the application exits quickly",
@@ -182,7 +182,7 @@
"lossless_scaling_legacy_auto_detect_label": "Use legacy Lossless auto-detection",
"lossless_scaling_legacy_auto_detect_desc": "Uses a timer-based auto-apply flow instead of the Lossless Scaling hotkey. Not recommended unless the hotkey method fails, because detection can be less reliable.",
"cert": "Certificate",
- "cert_desc": "The certificate used for the web UI and Moonlight client pairing. For best compatibility, this should have an RSA-2048 public key.",
+ "cert_desc": "The certificate used for the web UI and compatible client pairing. For best compatibility, this should have an RSA-2048 public key.",
"channels": "Maximum Connected Clients",
"channels_desc_1": "Nimbus can allow a single streaming session to be shared with multiple clients simultaneously.",
"channels_desc_2": "Some hardware encoders may have limitations that reduce performance with multiple streams.",
@@ -317,7 +317,7 @@
"hevc_mode_3": "Nimbus will advertise support for HEVC Main and Main10 (HDR) profiles",
"hevc_mode_desc": "Allows the client to request HEVC Main or HEVC Main10 video streams. HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.",
"high_resolution_scrolling": "High Resolution Scrolling Support",
- "high_resolution_scrolling_desc": "When enabled, Nimbus will pass through high resolution scroll events from Moonlight clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
+ "high_resolution_scrolling_desc": "When enabled, Nimbus will pass through high resolution scroll events from compatible clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
"install_steam_audio_drivers": "Install Steam Audio Drivers",
"install_steam_audio_drivers_desc": "If Steam is installed, this will automatically install the Steam Streaming Speakers driver to support 5.1/7.1 surround sound and muting host audio.",
"key_repeat_delay": "Key Repeat Delay",
@@ -325,7 +325,7 @@
"key_repeat_frequency": "Key Repeat Frequency",
"key_repeat_frequency_desc": "How often keys repeat every second. This configurable option supports decimals.",
"key_rightalt_to_key_win": "Map Right Alt key to Windows key",
- "key_rightalt_to_key_win_desc": "It may be possible that you cannot send the Windows Key from Moonlight directly. In those cases it may be useful to make Nimbus think the Right Alt key is the Windows key",
+ "key_rightalt_to_key_win_desc": "Some clients cannot send the Windows key directly. In those cases it may be useful to make Nimbus think the Right Alt key is the Windows key",
"keyboard": "Enable Keyboard Input",
"keyboard_desc": "Allows guests to control the host system with the keyboard",
"lan_encryption_mode": "LAN Encryption Mode",
@@ -356,7 +356,7 @@
"session_history_db_size_limit_mb": "Session History DB Size Limit (MiB)",
"session_history_db_size_limit_mb_desc": "Approximate live size limit for the session history database. Oldest ended sessions are pruned when the database grows past this limit. Set 0 to disable size-based pruning.",
"max_bitrate": "Maximum Bitrate",
- "max_bitrate_desc": "The maximum bitrate (in Kbps) that Nimbus will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.",
+ "max_bitrate_desc": "The maximum bitrate (in Kbps) that Nimbus will encode the stream at. If set to 0, it will always use the bitrate requested by the client.",
"min_threads": "Minimum CPU Thread Count",
"min_threads_desc": "Increasing the value slightly reduces encoding efficiency, but the tradeoff is usually worth it to gain the use of more CPU cores for encoding. The ideal value is the lowest value that can reliably encode at your desired streaming settings on your hardware.",
"misc": "Miscellaneous options",
@@ -365,7 +365,7 @@
"mouse": "Enable Mouse Input",
"mouse_desc": "Allows guests to control the host system with the mouse",
"native_pen_touch": "Native Pen/Touch Support",
- "native_pen_touch_desc": "When enabled, Nimbus will pass through native pen/touch events from Moonlight clients. This can be useful to disable for older applications without native pen/touch support.",
+ "native_pen_touch_desc": "When enabled, Nimbus will pass through native pen/touch events from compatible clients. This can be useful to disable for older applications without native pen/touch support.",
"notify_pre_releases": "PreRelease Notifications",
"notify_pre_releases_desc": "Whether to be notified of new pre-release versions of Nimbus",
"nvenc_h264_cavlc": "Prefer CAVLC over CABAC in H.264",
@@ -373,7 +373,7 @@
"nvenc_latency_over_power": "Prefer lower encoding latency over power savings",
"nvenc_latency_over_power_desc": "Nimbus requests maximum GPU clock speed while streaming to reduce encoding latency. Disabling it is not recommended since this can lead to significantly increased encoding latency.",
"nvenc_opengl_vulkan_on_dxgi": "Present OpenGL/Vulkan on top of DXGI",
- "nvenc_opengl_vulkan_on_dxgi_desc": "Nimbus can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted on sunshine program exit.",
+ "nvenc_opengl_vulkan_on_dxgi_desc": "Nimbus can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted when Nimbus exits.",
"nvenc_preset": "Performance preset",
"nvenc_preset_1": "(fastest, default)",
"nvenc_preset_4": "(balanced quality)",
@@ -391,7 +391,7 @@
"nvenc_twopass_full_res": "Full resolution (slower)",
"nvenc_twopass_quarter_res": "Quarter resolution (faster, default)",
"nvenc_vbv_increase": "Single-frame VBV/HRD percentage increase",
- "nvenc_vbv_increase_desc": "By default sunshine uses single-frame VBV/HRD, which means any encoded video frame size is not expected to exceed requested bitrate divided by requested frame rate. Relaxing this restriction can be beneficial and act as low-latency variable bitrate, but may also lead to packet loss if the network doesn't have buffer headroom to handle bitrate spikes. Maximum accepted value is 400, which corresponds to 5x increased encoded video frame upper size limit.",
+ "nvenc_vbv_increase_desc": "By default Nimbus uses single-frame VBV/HRD, which means any encoded video frame size is not expected to exceed requested bitrate divided by requested frame rate. Relaxing this restriction can be beneficial and act as low-latency variable bitrate, but may also lead to packet loss if the network doesn't have buffer headroom to handle bitrate spikes. Maximum accepted value is 400, which corresponds to 5x increased encoded video frame upper size limit.",
"origin_web_ui_allowed": "Origin Web UI Allowed",
"origin_web_ui_allowed_desc": "The origin of the remote endpoint address that is not denied access to Web UI",
"origin_web_ui_allowed_lan": "Only those in LAN may access Web UI",
@@ -406,12 +406,12 @@
"video_max_batch_size_kb": "Max Video Batch Size",
"video_max_batch_size_kb_desc": "Maximum size in KiB for each outgoing video send batch. The default is 64 KiB. Lower values can improve stream stability on cheaper switches, routers, and Wi-Fi gear, at the cost of less than 1 ms of extra host-side delay.",
"pkey": "Private Key",
- "pkey_desc": "The private key used for the web UI and Moonlight client pairing. For best compatibility, this should be an RSA-2048 private key.",
+ "pkey_desc": "The private key used for the web UI and compatible client pairing. For best compatibility, this should be an RSA-2048 private key.",
"port": "Port",
"port_alert_1": "Nimbus cannot use ports below 1024!",
"port_alert_2": "Ports above 65535 are not available!",
"port_desc": "Set the family of ports used by Nimbus",
- "port_http_port_note": "Use this port to connect with Moonlight.",
+ "port_http_port_note": "Use this port to connect from compatible clients.",
"port_note": "Note",
"port_port": "Port",
"port_protocol": "Protocol",
@@ -436,7 +436,7 @@
"stream_audio": "Stream Audio",
"stream_audio_desc": "Whether to stream audio or not. Disabling this can be useful for streaming headless displays as second monitors.",
"sunshine_name": "Nimbus Name",
- "sunshine_name_desc": "The name displayed by Moonlight. If not specified, the PC's hostname is used",
+ "sunshine_name_desc": "The host name shown in compatible clients. If not specified, the PC's hostname is used",
"sw_preset": "SW Presets",
"sw_preset_desc": "Optimize the trade-off between encoding speed (encoded frames per second) and compression efficiency (quality per bit in the bitstream). Defaults to superfast.",
"sw_preset_fast": "fast",
@@ -586,7 +586,7 @@
"server_cmd": "Server Commands",
"server_cmd_desc": "Configure a list of commands to be executed when called from client during streaming.",
"enable_pairing": "Enable Pairing",
- "enable_pairing_desc": "Enable pairing for the Moonlight client. This allows the client to authenticate with the host and establish a secure connection.",
+ "enable_pairing_desc": "Enable pairing for compatible clients. This allows the client to authenticate with the host and establish a secure connection.",
"enable_discovery": "Enable Auto Discovery",
"enable_discovery_desc": "When disabled, you'll need to manually enter host IP on the client to pair.",
"enable_input_only_mode": "Enable Input Only Mode",
@@ -608,7 +608,7 @@
"ignore_encoder_probe_failure": "Ignore Encoder Probe Failure",
"ignore_encoder_probe_failure_desc": "Allow streaming to continue even if probing for encoders fails. This may result in streaming failure if no encoder is available.",
"legacy_ordering": "App ordering for legacy clients",
- "legacy_ordering_desc": "Enable ordering support workaround for legacy clients. Can cause issues with clients or scripts that can't handle UTF8 correctly. Artemis clients support this by default."
+ "legacy_ordering_desc": "Enable ordering support workaround for legacy clients. Can cause issues with clients or scripts that can't handle UTF8 correctly. Modern compatible clients support this by default."
},
"index": {
"description": "Nimbus is a self-hosted game stream host for Moonlight-compatible clients.",
@@ -648,7 +648,7 @@
"pin": {
"device_name": "Device Name",
"pair_failure": "Pairing Failed: Check if the PIN is typed correctly",
- "pair_success": "Success! Please check Moonlight to continue",
+ "pair_success": "Success! Please check the client to continue",
"pin_pairing": "PIN Pairing",
"send": "Send",
"warning_msg": "Make sure you have access to the client you are pairing with. This software can give total control to your computer, so be careful!",
@@ -703,7 +703,7 @@
"dd_golden_delete_error": "Failed to delete golden display snapshot.",
"dd_golden_refresh": "Check Again",
"force_close": "Force Close",
- "force_close_desc": "If Moonlight complains about an app currently running, force closing the app should fix the issue.",
+ "force_close_desc": "If a client reports that an app is already running, force closing the app should fix the issue.",
"force_close_error": "Error while closing Application",
"force_close_success": "Application Closed Successfully!",
"logs": "Logs",
@@ -1070,7 +1070,7 @@
"nav": "Clients",
"title": "Client Management",
"pair_title": "Pair Client",
- "pair_desc": "Enter the 4-digit PIN shown in Moonlight along with a friendly device name to pair this client.",
+ "pair_desc": "Enter the 4-digit PIN shown in the client along with a friendly device name to pair this client.",
"existing_title": "Paired Clients",
"connected": "Connected",
"last_seen": "Last seen: {time}",
diff --git a/src_assets/common/assets/web/public/assets/locale/en_US.json b/src_assets/common/assets/web/public/assets/locale/en_US.json
index 0d94d88b02..9e4686c93b 100644
--- a/src_assets/common/assets/web/public/assets/locale/en_US.json
+++ b/src_assets/common/assets/web/public/assets/locale/en_US.json
@@ -41,7 +41,7 @@
"add_cmds": "Add Commands",
"add_new": "Add New",
"app_name": "Application Name",
- "app_name_desc": "Application Name, as shown on Moonlight",
+ "app_name_desc": "Application name as shown in compatible clients",
"applications_desc": "Applications are refreshed only when Client is restarted",
"applications_title": "Applications",
"auto_detach": "Continue streaming if the application exits quickly",
@@ -182,7 +182,7 @@
"lossless_scaling_legacy_auto_detect_label": "Use legacy Lossless auto-detection",
"lossless_scaling_legacy_auto_detect_desc": "Uses a timer-based auto-apply flow instead of the Lossless Scaling hotkey. Not recommended unless the hotkey method fails, because detection can be less reliable.",
"cert": "Certificate",
- "cert_desc": "The certificate used for the web UI and Moonlight client pairing. For best compatibility, this should have an RSA-2048 public key.",
+ "cert_desc": "The certificate used for the web UI and compatible client pairing. For best compatibility, this should have an RSA-2048 public key.",
"channels": "Maximum Connected Clients",
"channels_desc_1": "Nimbus can allow a single streaming session to be shared with multiple clients simultaneously.",
"channels_desc_2": "Some hardware encoders may have limitations that reduce performance with multiple streams.",
@@ -327,7 +327,7 @@
"hevc_mode_3": "Nimbus will advertise support for HEVC Main and Main10 (HDR) profiles",
"hevc_mode_desc": "Allows the client to request HEVC Main or HEVC Main10 video streams. HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.",
"high_resolution_scrolling": "High Resolution Scrolling Support",
- "high_resolution_scrolling_desc": "When enabled, Nimbus will pass through high resolution scroll events from Moonlight clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
+ "high_resolution_scrolling_desc": "When enabled, Nimbus will pass through high resolution scroll events from compatible clients. This can be useful to disable for older applications that scroll too fast with high resolution scroll events.",
"install_steam_audio_drivers": "Install Steam Audio Drivers",
"install_steam_audio_drivers_desc": "If Steam is installed, this will automatically install the Steam Streaming Speakers driver to support 5.1/7.1 surround sound and muting host audio.",
"key_repeat_delay": "Key Repeat Delay",
@@ -335,7 +335,7 @@
"key_repeat_frequency": "Key Repeat Frequency",
"key_repeat_frequency_desc": "How often keys repeat every second. This configurable option supports decimals.",
"key_rightalt_to_key_win": "Map Right Alt key to Windows key",
- "key_rightalt_to_key_win_desc": "It may be possible that you cannot send the Windows Key from Moonlight directly. In those cases it may be useful to make Nimbus think the Right Alt key is the Windows key",
+ "key_rightalt_to_key_win_desc": "Some clients cannot send the Windows key directly. In those cases it may be useful to make Nimbus think the Right Alt key is the Windows key",
"keybindings": "Keybindings",
"keyboard": "Enable Keyboard Input",
"keyboard_desc": "Allows guests to control the host system with the keyboard",
@@ -348,7 +348,7 @@
"log_path": "Logfile Path",
"log_path_desc": "The file where the current logs of Nimbus are stored.",
"max_bitrate": "Maximum Bitrate",
- "max_bitrate_desc": "The maximum bitrate (in Kbps) that Nimbus will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.",
+ "max_bitrate_desc": "The maximum bitrate (in Kbps) that Nimbus will encode the stream at. If set to 0, it will always use the bitrate requested by the client.",
"minimum_fps_target": "Minimum FPS Target",
"minimum_fps_target_desc": "The lowest effective FPS a stream can reach. A value of 0 is treated as roughly half of the stream's FPS. A setting of 20 is recommended if you stream 24 or 30fps content.",
"session_token_ttl_seconds": "Web UI Session Timeout (seconds)",
@@ -378,7 +378,7 @@
"mouse": "Enable Mouse Input",
"mouse_desc": "Allows guests to control the host system with the mouse",
"native_pen_touch": "Native Pen/Touch Support",
- "native_pen_touch_desc": "When enabled, Nimbus will pass through native pen/touch events from Moonlight clients. This can be useful to disable for older applications without native pen/touch support.",
+ "native_pen_touch_desc": "When enabled, Nimbus will pass through native pen/touch events from compatible clients. This can be useful to disable for older applications without native pen/touch support.",
"notify_pre_releases": "PreRelease Notifications",
"notify_pre_releases_desc": "Whether to be notified of new pre-release versions of Nimbus",
"nvenc_h264_cavlc": "Prefer CAVLC over CABAC in H.264",
@@ -386,7 +386,7 @@
"nvenc_latency_over_power": "Prefer lower encoding latency over power savings",
"nvenc_latency_over_power_desc": "Nimbus requests maximum GPU clock speed while streaming to reduce encoding latency. Disabling it is not recommended since this can lead to significantly increased encoding latency.",
"nvenc_opengl_vulkan_on_dxgi": "Present OpenGL/Vulkan on top of DXGI",
- "nvenc_opengl_vulkan_on_dxgi_desc": "Nimbus can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted on sunshine program exit.",
+ "nvenc_opengl_vulkan_on_dxgi_desc": "Nimbus can't capture fullscreen OpenGL and Vulkan programs at full frame rate unless they present on top of DXGI. This is system-wide setting that is reverted when Nimbus exits.",
"nvenc_preset": "Performance preset",
"nvenc_preset_1": "(fastest, default)",
"nvenc_preset_4": "(balanced quality)",
@@ -405,7 +405,7 @@
"nvenc_twopass_full_res": "Full resolution (slower)",
"nvenc_twopass_quarter_res": "Quarter resolution (faster, default)",
"nvenc_vbv_increase": "Single-frame VBV/HRD percentage increase",
- "nvenc_vbv_increase_desc": "By default sunshine uses single-frame VBV/HRD, which means any encoded video frame size is not expected to exceed requested bitrate divided by requested frame rate. Relaxing this restriction can be beneficial and act as low-latency variable bitrate, but may also lead to packet loss if the network doesn't have buffer headroom to handle bitrate spikes. Maximum accepted value is 400, which corresponds to 5x increased encoded video frame upper size limit.",
+ "nvenc_vbv_increase_desc": "By default Nimbus uses single-frame VBV/HRD, which means any encoded video frame size is not expected to exceed requested bitrate divided by requested frame rate. Relaxing this restriction can be beneficial and act as low-latency variable bitrate, but may also lead to packet loss if the network doesn't have buffer headroom to handle bitrate spikes. Maximum accepted value is 400, which corresponds to 5x increased encoded video frame upper size limit.",
"origin_web_ui_allowed": "Origin Web UI Allowed",
"origin_web_ui_allowed_desc": "The origin of the remote endpoint address that is not denied access to Web UI",
"origin_web_ui_allowed_lan": "Only those in LAN may access Web UI",
@@ -419,12 +419,12 @@
"video_max_batch_size_kb": "Max Video Batch Size",
"video_max_batch_size_kb_desc": "Maximum size in KiB for each outgoing video send batch. The default is 64 KiB. Lower values can improve stream stability on cheaper switches, routers, and Wi-Fi gear, at the cost of less than 1 ms of extra host-side delay.",
"pkey": "Private Key",
- "pkey_desc": "The private key used for the web UI and Moonlight client pairing. For best compatibility, this should be an RSA-2048 private key.",
+ "pkey_desc": "The private key used for the web UI and compatible client pairing. For best compatibility, this should be an RSA-2048 private key.",
"port": "Port",
"port_alert_1": "Nimbus cannot use ports below 1024!",
"port_alert_2": "Ports above 65535 are not available!",
"port_desc": "Set the family of ports used by Nimbus",
- "port_http_port_note": "Use this port to connect with Moonlight.",
+ "port_http_port_note": "Use this port to connect from compatible clients.",
"port_note": "Note",
"port_port": "Port",
"port_protocol": "Protocol",
@@ -449,7 +449,7 @@
"stream_audio": "Stream Audio",
"stream_audio_desc": "Whether to stream audio or not. Disabling this can be useful for streaming headless displays as second monitors.",
"sunshine_name": "Nimbus Name",
- "sunshine_name_desc": "The name displayed by Moonlight. If not specified, the PC's hostname is used",
+ "sunshine_name_desc": "The host name shown in compatible clients. If not specified, the PC's hostname is used",
"sw_preset": "SW Presets",
"sw_preset_desc": "Optimize the trade-off between encoding speed (encoded frames per second) and compression efficiency (quality per bit in the bitstream). Defaults to superfast.",
"sw_preset_fast": "fast",
@@ -575,7 +575,7 @@
"server_cmd": "Server Commands",
"server_cmd_desc": "Configure a list of commands to be executed when called from client during streaming.",
"enable_pairing": "Enable Pairing",
- "enable_pairing_desc": "Enable pairing for the Moonlight client. This allows the client to authenticate with the host and establish a secure connection.",
+ "enable_pairing_desc": "Enable pairing for compatible clients. This allows the client to authenticate with the host and establish a secure connection.",
"enable_discovery": "Enable Auto Discovery",
"enable_discovery_desc": "When disabled, you'll need to manually enter host IP on the client to pair.",
"enable_input_only_mode": "Enable Input Only Mode",
@@ -597,7 +597,7 @@
"ignore_encoder_probe_failure": "Ignore Encoder Probe Failure",
"ignore_encoder_probe_failure_desc": "Allow streaming to continue even if probing for encoders fails. This may result in streaming failure if no encoder is available.",
"legacy_ordering": "App ordering for legacy clients",
- "legacy_ordering_desc": "Enable ordering support workaround for legacy clients. Can cause issues with clients or scripts that can't handle UTF8 correctly. Artemis clients support this by default."
+ "legacy_ordering_desc": "Enable ordering support workaround for legacy clients. Can cause issues with clients or scripts that can't handle UTF8 correctly. Modern compatible clients support this by default."
},
"index": {
"description": "Nimbus is a self-hosted game stream host for Moonlight-compatible clients.",
@@ -644,7 +644,7 @@
"pin": {
"device_name": "Device Name",
"pair_failure": "Pairing Failed: Check if the PIN is typed correctly",
- "pair_success": "Success! Please check Moonlight to continue",
+ "pair_success": "Success! Please check the client to continue",
"pin_pairing": "PIN Pairing",
"send": "Send",
"warning_msg": "Make sure you have access to the client you are pairing with. This software can give total control to your computer, so be careful!",
@@ -700,7 +700,7 @@
"dd_golden_delete_error": "Failed to delete golden display snapshot.",
"dd_golden_refresh": "Check Again",
"force_close": "Force Close",
- "force_close_desc": "If Moonlight complains about an app currently running, force closing the app should fix the issue.",
+ "force_close_desc": "If a client reports that an app is already running, force closing the app should fix the issue.",
"force_close_error": "Error while closing Application",
"force_close_success": "Application Closed Successfully!",
"logs": "Logs",
@@ -947,7 +947,7 @@
"nav": "Clients",
"title": "Client Management",
"pair_title": "Pair Client",
- "pair_desc": "Enter the 4-digit PIN shown in Moonlight along with a friendly device name to pair this client.",
+ "pair_desc": "Enter the 4-digit PIN shown in the client along with a friendly device name to pair this client.",
"existing_title": "Paired Clients",
"connected": "Connected",
"last_seen": "Last seen: {time}",
From 8cc62a2e594275b0fab02b724d1322cbbefb2ccf Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Sat, 23 May 2026 01:16:18 +1000
Subject: [PATCH 30/60] docs: define setup intelligence roadmap
---
README.md | 2 +
ROADMAP.md | 5 +-
docs/community-research.md | 186 ++++++++++++++++++
.../setup-doctor-client-profiles.md | 73 +++++++
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 4 +
.../common/assets/web/Troubleshooting.vue | 59 ++++++
.../assets/web/public/assets/locale/en.json | 7 +
.../web/public/assets/locale/en_GB.json | 7 +
.../web/public/assets/locale/en_US.json | 7 +
.../common/assets/web/views/DashboardView.vue | 4 +-
10 files changed, 351 insertions(+), 3 deletions(-)
create mode 100644 docs/community-research.md
create mode 100644 docs/roadmap-issues/setup-doctor-client-profiles.md
diff --git a/README.md b/README.md
index c4f3b98be2..53d63dd6a8 100644
--- a/README.md
+++ b/README.md
@@ -73,6 +73,8 @@ Early Nimbus work is focused on:
- Preparing the future Lucent client track.
See [ROADMAP.md](ROADMAP.md) for the current maintainer roadmap.
+See [docs/community-research.md](docs/community-research.md) for the community
+setup research behind Setup Doctor, Client Profiles, and future fixture work.
See [docs/ui-identity-plan.md](docs/ui-identity-plan.md) for the staged Nimbus
Web UI identity direction.
diff --git a/ROADMAP.md b/ROADMAP.md
index 47efc6d504..f3a2dd237f 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -42,6 +42,8 @@ Goal: build maintainer credibility through user-visible stability work.
- Prioritize Windows 11, NVIDIA Shield TV Pro, Android TV, and Moonlight/Artemis
compatibility reports.
+- Turn community setup pain into guided diagnostics, starting with Setup Doctor,
+ Client Profiles, Cursor Doctor, and a fixture matrix.
- Improve logs and diagnostics before changing capture behavior.
- Create reproducible issue templates for frame pacing, WGC, virtual display,
HDR, audio, controller, and Playnite issues.
@@ -72,7 +74,8 @@ The next engineering pass should validate the package-branding slice from
`docs/packaging-identity-plan.md` before any branded Nimbus release:
1. Use `docs/release-build-audit.md` as the release automation baseline.
-2. Use `docs/upstream-issue-radar.md` to choose the first reliability issue.
+2. Use `docs/community-research.md` and `docs/upstream-issue-radar.md` to choose
+ the first reliability issue.
3. Confirm runtime identifiers remained unchanged unless the packaging identity
plan says the migration has a test path.
4. Produce a local Nimbus-named installer and inspect install, upgrade, and
diff --git a/docs/community-research.md b/docs/community-research.md
new file mode 100644
index 0000000000..de6ea2cfe3
--- /dev/null
+++ b/docs/community-research.md
@@ -0,0 +1,186 @@
+# Nimbus Community Research
+
+Snapshot date: 2026-05-23
+
+This document turns community setup patterns into Nimbus product direction. It
+is not a promise that Nimbus will replace every upstream feature. The goal is to
+identify where Nimbus can be meaningfully different from Vibepollo, Apollo, and
+Sunshine while staying useful to Moonlight-compatible clients.
+
+## Positioning
+
+Nimbus should become the guided, validated, profile-driven host fork:
+
+> Tell Nimbus what you stream to, and Nimbus tells you the correct display,
+> bitrate, audio, controller, and network setup. If something is wrong, Nimbus
+> explains why.
+
+That is different from simply adding more power-user toggles. Vibepollo already
+leans into fast feature expansion around Playnite, RTSS/NVIDIA Control Panel,
+WGC/frame-generation workarounds, Lossless Scaling, WebRTC, API tokens, and
+session auth. Nimbus can stand out by making the messy community setup ritual
+inspectable, repeatable, and easier to support.
+
+```mermaid
+flowchart LR
+ A["Community setup pain"] --> B["Nimbus Setup Doctor"]
+ A --> C["Client Profiles"]
+ A --> D["Streaming Recipes"]
+ A --> E["Fixture Matrix"]
+
+ B --> F["Trustworthy host fork"]
+ C --> F
+ D --> F
+ E --> F
+```
+
+## Observed Setup Clusters
+
+| Cluster | Typical Shape | Nimbus Opportunity |
+| --- | --- | --- |
+| Living-room console | Windows host to Shield TV, Android TV, Xbox, or mini PC at 4K60/4K120 | Presets for TV clients, controller-first apps, and safe cursor handling. |
+| Handheld | Steam Deck, phones, tablets, Logitech G Cloud, 720p/800p/1200p/90Hz | Device profiles and bitrate/refresh recommendations. |
+| OLED/HDR enthusiast | 4K120 HDR, dummy plugs, virtual displays, AV1/HEVC, EDID tuning | HDR/display doctor and validated 10-bit/HDR checks. |
+| Headless host | No monitor, SudoVDA/VDD, dummy HDMI/DP, VM/GPU passthrough | Virtual-display lifecycle diagnostics and recovery warnings. |
+| Remote home/cloud | Tailscale, WireGuard, ZeroTier, WAN pairing, mobile networks | Network path diagnostics and support boundaries. |
+| Library launcher | Playnite, Steam Big Picture, LaunchBox, emulators, Xbox/Game Pass | Library integration status, import safety, and clean launch/exit guidance. |
+| Performance tuning | RTSS frame caps, fractional refresh, WGC/DXGI, Lossless Scaling | Frame pacing assistant with observable reasons. |
+| Family/local multiplayer | Multiple controllers on Android TV/Shield/Google TV | Controller doctor and Player 1 conflict checks. |
+
+## Repeated Pain Points
+
+### Display And HDR
+
+Users often bounce between SudoVDA, MikeTheTech VDD, dummy plugs, physical
+monitors, EDID exports, HDR calibration, and app-specific display overrides.
+The real pain is not only whether a setting exists, but whether the user knows
+which display Nimbus is capturing, which display was changed, and whether the
+restore path is trustworthy.
+
+### Frame Pacing
+
+Frame pacing advice is scattered across wikis and forum comments: 59.94 vs 60,
+119.88 vs 120, RTSS caps, WGC vs DXGI behavior, VRR/G-Sync, Wi-Fi power-saving,
+and client-native refresh. Nimbus should surface this as a guided check instead
+of leaving users to infer it from symptoms.
+
+### Audio
+
+Stereo, 5.1, 7.1, Steam Streaming Speakers, virtual sinks, eARC/soundbars,
+Bluetooth delay, and app-specific routing are recurring support traps. Nimbus
+should make audio mode, selected sink, and likely downmix paths easier to see.
+
+### Controllers
+
+ViGEmBus, host-attached physical controllers, player-order conflicts, multiple
+controllers collapsing into one, Android TV mappings, Steam Input, and DualSense
+features all create confusing failures. Nimbus needs a controller health view
+before it needs more hidden input knobs.
+
+### Cursor Persistence
+
+The Windows cursor can remain visible, disappear, duplicate, offset, or be
+confused with the client-side cursor. This appears across host/client streaming
+stacks, especially with desktop mode, touchscreen/touchpad mode, Android
+clients, HDR/virtual displays, and games that draw their own cursor.
+
+Nimbus should start with diagnostics and safe workarounds:
+
+- Explain the difference between host cursor, client cursor, and game cursor.
+- Link to client-side cursor toggles where applicable.
+- Offer per-app guidance for controller-first games.
+- Consider a low-risk "move cursor to safe corner on launch" policy before any
+ invasive cursor-hiding behavior.
+
+### Network
+
+Users can often say "Tailscale works" or "stream failed," but not whether they
+are direct, relayed, firewalled, blocked by RTSP, or using the wrong address.
+Nimbus should eventually report network path hints, open ports, and support
+boundaries for overlay networks.
+
+### Install And Update Trust
+
+Unsigned installers, UAC, driver installation, archived ViGEmBus status,
+SudoVDA, service identity, and inherited project names affect trust. Nimbus
+should keep release notes honest and make rollback/update behavior predictable.
+
+## What Existing Projects Already Cover
+
+| Project | Useful Coverage | Nimbus Lesson |
+| --- | --- | --- |
+| Sunshine | Cross-platform host, mature configuration docs, apps, network setup, audio/input knobs. | Do not duplicate docs blindly; add guided diagnostics around the knobs. |
+| Apollo | SudoVDA-oriented virtual display, Artemis workflow, display override docs, stutter guidance. | Virtual display and frame pacing are primary host responsibilities. |
+| Vibepollo | Playnite sync, RTSS/NVCP integration, WGC/frame-generation fixes, Lossless Scaling, WebRTC, scoped API tokens, session auth, update checks. | Avoid chasing every power-user toggle; focus on setup intelligence and validation. |
+| Moonlight/Artemis | Client settings, controller behavior, native FPS, HDR, cursor toggles, platform-specific quirks. | Nimbus should stay compatible and explain client-side fixes without pretending Lucent exists yet. |
+| Playnite | Library plugins, emulator auto-scan, metadata, covers, categories, exclusions. | Prefer Playnite for library truth; add a safer Discovery Inbox for non-Playnite users later. |
+
+## Feature Ranking
+
+| Rank | Feature | Impact | Effort | Risk | First Deliverable |
+| ---: | --- | --- | --- | --- | --- |
+| 1 | Nimbus Setup Doctor | Very high | Medium | Low | Read-only health report with display, encoder, driver, ports, logs, and warnings. |
+| 2 | Client Profiles | Very high | Medium | Medium | Preset docs and UI labels for Shield TV, Steam Deck, Android TV, phone/tablet, mini PC. |
+| 3 | Pairing deep-link UX | High | Low | Low | Toast opens Clients page at Pair Client section and focuses the PIN flow. |
+| 4 | Streaming Recipe Library | High | Low | Low | Markdown recipes for common setups with known-good defaults. |
+| 5 | Frame Pacing Assistant | High | Medium | Medium | Detect requested FPS vs display refresh and recommend safe caps. |
+| 6 | Audio Routing Wizard | High | Medium | Low | Show selected sink, channel mode, and common downmix checks. |
+| 7 | Controller Doctor | High | Medium | Low | Show ViGEm status, host controller warning, and multi-controller notes. |
+| 8 | Safe Update/Rollback Channel | Medium-high | Medium | Low | Release channel docs, rollback notes, and service/driver preservation checks. |
+| 9 | Game Discovery Inbox | Medium-high | Medium | Medium | Read-only candidate list before any import writes to `apps.json`. |
+| 10 | Community Fixture Matrix | Medium | Low-medium | Low | Public table of tested host/client/display/network combos. |
+
+## Game Discovery Inbox
+
+Vibepollo already covers a large Playnite-based import path. Nimbus should not
+blindly scan every `.exe` and add false positives. The safer Nimbus version is a
+review inbox:
+
+```mermaid
+flowchart TD
+ A["Known sources"] --> B["Steam/Epic/GOG manifests"]
+ A --> C["Playnite library"]
+ A --> D["User-selected folders"]
+ D --> E["Heuristic executable candidates"]
+ B --> F["Discovery Inbox"]
+ C --> F
+ E --> F
+ F --> G["Select, deselect, all, none"]
+ G --> H["Import selected apps"]
+ H --> I["Undo last import batch"]
+```
+
+Candidate confidence should be explicit:
+
+- `High`: launcher manifest or Playnite entry with install metadata.
+- `Medium`: known game folder pattern with one likely executable.
+- `Low`: directory heuristic with multiple executables or launchers.
+
+The first implementation should be read-only and write no apps until the UI and
+candidate scoring are reviewed.
+
+## Sources
+
+- [Vibepollo README](https://github.com/Nonary/Vibepollo)
+- [Sunshine configuration docs](https://docs.lizardbyte.dev/projects/sunshine/master/md_docs_2configuration.html?lng=en-US)
+- [Moonlight Setup Guide](https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide)
+- [Moonlight Android releases](https://github.com/moonlight-stream/moonlight-android/releases)
+- [Apollo README](https://github.com/ClassicOldSong/Apollo)
+- [Apollo Display Mode Override](https://github.com/ClassicOldSong/Apollo/wiki/Display-Mode-Override)
+- [Apollo Stuttering Clinic](https://github.com/ClassicOldSong/Apollo/wiki/Stuttering-Clinic)
+- [Apollo Profile Manager](https://github.com/ClassicOldSong/ApolloProfileManager)
+- [Vibepollo over Apollo discussion](https://www.reddit.com/r/MoonlightStreaming/comments/1r0p1g1/any_benefits_for_using_vibepollo_over_apollo/)
+- [Switching to Vibepollo discussion](https://www.reddit.com/r/MoonlightStreaming/comments/1pu61b2/has_anyone_made_the_switch_from_using/)
+- [Vibeshine vs Vibepollo discussion](https://www.reddit.com/r/MoonlightStreaming/comments/1qyhvgd/differences_between_vibeshine_vs_vibepollo_and/)
+- [Sunshine cursor issue 1940](https://github.com/LizardByte/Sunshine/issues/1940)
+- [Playnite PC auto-scan discussion](https://www.reddit.com/r/playnite/comments/18mokqc/is_auto_scan_of_pc_windows_games_possible/)
+- [Playnite emulated game auto-scan docs](https://api.playnite.link/docs/manual/features/emulationSupport/addingEmulatedGames.html)
+
+## Next Actions
+
+1. Open a public roadmap issue for Setup Doctor and Client Profiles.
+2. Keep the first implementation read-only wherever possible.
+3. Add a Troubleshooting page cursor card as the first visible Setup Doctor seed.
+4. Create a fixture matrix after the next VM build and Shield TV stream test.
+5. Treat upstream Vibepollo display/HDR/session fixes as sync candidates, not
+ automatic merges.
diff --git a/docs/roadmap-issues/setup-doctor-client-profiles.md b/docs/roadmap-issues/setup-doctor-client-profiles.md
new file mode 100644
index 0000000000..3eea726b85
--- /dev/null
+++ b/docs/roadmap-issues/setup-doctor-client-profiles.md
@@ -0,0 +1,73 @@
+# Roadmap: Nimbus Setup Doctor And Client Profiles
+
+## Problem
+
+Nimbus should not compete with Vibepollo by adding another pile of hidden
+toggles. Community setup pain is mostly about knowing which settings matter for
+a specific host/client setup and how to diagnose failures.
+
+Users repeatedly struggle with:
+
+- virtual display and HDR state,
+- frame pacing and refresh-rate mismatches,
+- audio sink/channel routing,
+- ViGEm/controller conflicts,
+- persistent or missing cursors,
+- LAN/WAN/Tailscale/WireGuard path confusion,
+- Playnite/library import expectations,
+- unsigned installer and driver trust.
+
+## Goal
+
+Make Nimbus the guided, validated, profile-driven host fork:
+
+> Tell Nimbus what you stream to, and Nimbus tells you the correct display,
+> bitrate, audio, controller, and network setup. If something is wrong, Nimbus
+> explains why.
+
+## Proposed Scope
+
+### Phase 1: Read-Only Setup Doctor
+
+- Show GPU/encoder summary.
+- Show active capture/display target and virtual display status.
+- Show HDR/10-bit capability and current stream setup when available.
+- Show ViGEm/SudoVDA presence and warnings.
+- Show selected audio sink and channel mode.
+- Show basic firewall/port checks.
+- Show current log bundle/export entry point.
+- Add a Cursor Doctor troubleshooting card.
+
+### Phase 2: Client Profiles
+
+- Add known setup profiles for:
+ - Shield TV / Android TV 4K60,
+ - Shield TV / Android TV 4K120 where supported,
+ - Steam Deck / handheld,
+ - phone/tablet,
+ - mini PC client,
+ - headless Windows host,
+ - remote Tailscale/WireGuard.
+- Start as recommendations and docs before automatic config writes.
+
+### Phase 3: Game Discovery Inbox
+
+- Present read-only game/app candidates from known sources.
+- Prefer Playnite and launcher manifests over blind `.exe` scanning.
+- Let users select/deselect/all/none before importing.
+- Track imported batch metadata so users can undo.
+
+## Acceptance Criteria
+
+- First pass is safe to run on an existing Apollo/Vibepollo/Nimbus config.
+- No automatic config writes happen without an explicit confirm step.
+- Each warning includes a concrete next action.
+- Fixture matrix records at least one real Shield TV / Artemis stream result.
+- Documentation links back to `docs/community-research.md`.
+
+## References
+
+- `docs/community-research.md`
+- `docs/upstream-issue-radar.md`
+- `docs/windows-installer-fixture.md`
+- `docs/naming-identity-audit.md`
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index 2e30c82a73..7095a21018 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -48,6 +48,10 @@ has wider testers.
- Added a naming identity audit for inherited Sunshine, Vibeshine, Moonlight,
Artemis, Apollo, and Vibepollo surfaces, then cleaned low-risk visible Web UI
settings copy, placeholders, and Web UI package metadata.
+- Added community research and a roadmap issue draft for Setup Doctor, Client
+ Profiles, Cursor Doctor, and the future Game Discovery Inbox direction.
+- Added the first Cursor Doctor card to the Troubleshooting page and cleaned
+ remaining Playnite cleanup copy that still said Vibeshine.
## Compatibility Notes
diff --git a/src_assets/common/assets/web/Troubleshooting.vue b/src_assets/common/assets/web/Troubleshooting.vue
index e9194baf50..0ed4714cc9 100644
--- a/src_assets/common/assets/web/Troubleshooting.vue
+++ b/src_assets/common/assets/web/Troubleshooting.vue
@@ -65,6 +65,58 @@
+ {{
+ translate(
+ 'troubleshooting.cursor_doctor_desc',
+ 'If the Windows cursor remains visible, disappears, or duplicates during a stream, start by separating host cursor, client cursor, and game cursor behavior.',
+ )
+ }}
+
+ {{
+ translate(
+ 'troubleshooting.cursor_doctor_host',
+ 'Host cursor: Windows pointer captured from the streaming PC.',
+ )
+ }}
+
+
+ {{
+ translate(
+ 'troubleshooting.cursor_doctor_client',
+ 'Client cursor: local pointer overlay or touch/trackpad cursor from the client app.',
+ )
+ }}
+
+
+ {{
+ translate(
+ 'troubleshooting.cursor_doctor_game',
+ 'Game cursor: a cursor drawn by the game itself, often independent of Windows.',
+ )
+ }}
+
+
+
+
@@ -693,6 +745,13 @@ function clearSearch() {
searchTerm.value = '';
}
+async function focusLogSearch(term: string) {
+ logSource.value = 'sunshine';
+ logFilter.value = term;
+ await nextTick();
+ logScrollbar.value?.scrollTo?.({ top: 0 });
+}
+
function cancelSearchTask() {
searchTaskId += 1;
searchInProgress.value = false;
diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json
index b9045e384c..eb17e5b207 100644
--- a/src_assets/common/assets/web/public/assets/locale/en.json
+++ b/src_assets/common/assets/web/public/assets/locale/en.json
@@ -1147,6 +1147,13 @@
"export_logs": "Export Logs",
"collect_playnite_logs": "Export Logs",
"collect_playnite_logs_desc": "Export Nimbus log, Playnite/plugin logs, and display-helper logs.",
+ "cursor_doctor": "Cursor Doctor",
+ "cursor_doctor_desc": "If the Windows cursor remains visible, disappears, or duplicates during a stream, start by separating host cursor, client cursor, and game cursor behavior.",
+ "cursor_doctor_host": "Host cursor: Windows pointer captured from the streaming PC.",
+ "cursor_doctor_client": "Client cursor: local pointer overlay or touch/trackpad cursor from the client app.",
+ "cursor_doctor_game": "Game cursor: a cursor drawn by the game itself, often independent of Windows.",
+ "search_cursor_logs": "Search cursor logs",
+ "search_mouse_logs": "Search mouse logs",
"export_crash_bundle": "Export Crash Bundle",
"export_crash_bundle_preparing": "Preparing Crash Bundle...",
"export_crash_bundle_desc": "Download logs along with the most recent Nimbus crash dump.",
diff --git a/src_assets/common/assets/web/public/assets/locale/en_GB.json b/src_assets/common/assets/web/public/assets/locale/en_GB.json
index 9deb095259..16dca4e3ba 100644
--- a/src_assets/common/assets/web/public/assets/locale/en_GB.json
+++ b/src_assets/common/assets/web/public/assets/locale/en_GB.json
@@ -737,6 +737,13 @@
"copy_logs": "Copy Logs",
"collect_playnite_logs": "Export Logs",
"collect_playnite_logs_desc": "Export Nimbus log, Playnite/plugin logs, and display-helper logs.",
+ "cursor_doctor": "Cursor Doctor",
+ "cursor_doctor_desc": "If the Windows cursor remains visible, disappears, or duplicates during a stream, start by separating host cursor, client cursor, and game cursor behavior.",
+ "cursor_doctor_host": "Host cursor: Windows pointer captured from the streaming PC.",
+ "cursor_doctor_client": "Client cursor: local pointer overlay or touch/trackpad cursor from the client app.",
+ "cursor_doctor_game": "Game cursor: a cursor drawn by the game itself, often independent of Windows.",
+ "search_cursor_logs": "Search cursor logs",
+ "search_mouse_logs": "Search mouse logs",
"export_crash_bundle": "Export Crash Bundle",
"export_crash_bundle_desc": "Download logs along with the most recent Nimbus crash dump."
},
diff --git a/src_assets/common/assets/web/public/assets/locale/en_US.json b/src_assets/common/assets/web/public/assets/locale/en_US.json
index 9e4686c93b..3a9f3993b2 100644
--- a/src_assets/common/assets/web/public/assets/locale/en_US.json
+++ b/src_assets/common/assets/web/public/assets/locale/en_US.json
@@ -734,6 +734,13 @@
"copy_logs": "Copy Logs",
"collect_playnite_logs": "Export Logs",
"collect_playnite_logs_desc": "Export Nimbus log, Playnite/plugin logs, and display-helper logs.",
+ "cursor_doctor": "Cursor Doctor",
+ "cursor_doctor_desc": "If the Windows cursor remains visible, disappears, or duplicates during a stream, start by separating host cursor, client cursor, and game cursor behavior.",
+ "cursor_doctor_host": "Host cursor: Windows pointer captured from the streaming PC.",
+ "cursor_doctor_client": "Client cursor: local pointer overlay or touch/trackpad cursor from the client app.",
+ "cursor_doctor_game": "Game cursor: a cursor drawn by the game itself, often independent of Windows.",
+ "search_cursor_logs": "Search cursor logs",
+ "search_mouse_logs": "Search mouse logs",
"export_crash_bundle": "Export Crash Bundle",
"export_crash_bundle_desc": "Download logs along with the most recent Nimbus crash dump."
},
diff --git a/src_assets/common/assets/web/views/DashboardView.vue b/src_assets/common/assets/web/views/DashboardView.vue
index e3d35c0cf6..8dc040d6bb 100644
--- a/src_assets/common/assets/web/views/DashboardView.vue
+++ b/src_assets/common/assets/web/views/DashboardView.vue
@@ -1058,7 +1058,7 @@ const playniteMissingPluginBannerText = computed(() => {
}
const detected =
details.length > 1 ? `${details[0]} and ${details[1]}` : (details[0] ?? 'Playnite entries');
- return `Detected ${detected}, but the Playnite plugin is no longer installed. Reinstall the plugin to restore integration, or purge Playnite games to remove all Playnite entries from Vibeshine.`;
+ return `Detected ${detected}, but the Playnite plugin is no longer installed. Reinstall the plugin to restore integration, or purge Playnite games to remove all Playnite entries from Nimbus.`;
});
async function resolvePlaynitePluginIssue() {
@@ -1129,7 +1129,7 @@ function openPurgePlayniteGamesConfirm() {
dialog.warning({
title: 'Purge Playnite games?',
content:
- 'This removes all Playnite entries from Vibeshine, including auto-synced games and the Playnite (Fullscreen) launcher.',
+ 'This removes all Playnite entries from Nimbus, including auto-synced games and the Playnite (Fullscreen) launcher.',
positiveText: 'Purge',
negativeText: 'Cancel',
onPositiveClick: async () => {
From 2f47bb81f7634190aa83d5ddf9b948534b736399 Mon Sep 17 00:00:00 2001
From: Chase Payne
Date: Mon, 18 May 2026 19:17:17 -0500
Subject: [PATCH 31/60] fix(nvenc): preserve legacy bit-depth layout for API
12.1
NVENC SDK 12.2 moved codec bit-depth fields, but 12.1 runtimes still expect the legacy packed layout.
Treat separate input/output bit-depth fields as available only for API 12.2+ so older drivers no longer reject HEVC Main10 probes. Update the API gate test to lock the compatibility boundary.
Generated with [Codex](https://openai.com/index/introducing-gpt-5-2-codex/)
Model: GPT 5.5 Codex high
(cherry picked from commit 6168f5fbcf41f4c04d6e417a2e22837afb30a114)
---
src/nvenc/nvenc_api.h | 1 -
src/nvenc/nvenc_base.cpp | 10 +++++-----
tests/unit/test_nvenc_api.cpp | 4 ++--
3 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/src/nvenc/nvenc_api.h b/src/nvenc/nvenc_api.h
index 6e46fc52c5..cef2aa30ac 100644
--- a/src/nvenc/nvenc_api.h
+++ b/src/nvenc/nvenc_api.h
@@ -137,7 +137,6 @@ namespace nvenc::api {
constexpr bool supports_separate_bit_depth_fields(uint32_t api_version) {
switch (api_version) {
- case make_api_version(12U, 1U):
case make_api_version(12U, 2U):
case make_api_version(13U, 0U):
return true;
diff --git a/src/nvenc/nvenc_base.cpp b/src/nvenc/nvenc_base.cpp
index 48df9f01a3..abc331a16d 100644
--- a/src/nvenc/nvenc_base.cpp
+++ b/src/nvenc/nvenc_base.cpp
@@ -509,12 +509,12 @@ namespace nvenc {
};
const auto set_hevc_10bit_format = [&](auto &format_config) {
-#if NVENCAPI_MAJOR_VERSION > 12 || (NVENCAPI_MAJOR_VERSION == 12 && NVENCAPI_MINOR_VERSION >= 1)
+#if NVENCAPI_MAJOR_VERSION > 12 || (NVENCAPI_MAJOR_VERSION == 12 && NVENCAPI_MINOR_VERSION >= 2)
if (api::supports_separate_bit_depth_fields(selected_api_version)) {
format_config.inputBitDepth = NV_ENC_BIT_DEPTH_10;
format_config.outputBitDepth = NV_ENC_BIT_DEPTH_10;
} else {
- // SDK 13 removed the old HEVC bit-depth field names, but the v11/v12.0
+ // SDK 12.2 removed the old HEVC bit-depth field names, but the v11/v12.1
// layout still occupies these reserved bits.
format_config.reserved3 = 2;
}
@@ -524,7 +524,7 @@ namespace nvenc {
};
const auto set_av1_10bit_format = [&](auto &format_config) {
-#if NVENCAPI_MAJOR_VERSION > 12 || (NVENCAPI_MAJOR_VERSION == 12 && NVENCAPI_MINOR_VERSION >= 1)
+#if NVENCAPI_MAJOR_VERSION > 12 || (NVENCAPI_MAJOR_VERSION == 12 && NVENCAPI_MINOR_VERSION >= 2)
format_config.inputBitDepth = NV_ENC_BIT_DEPTH_10;
format_config.outputBitDepth = NV_ENC_BIT_DEPTH_10;
#else
@@ -545,7 +545,7 @@ namespace nvenc {
} else {
format_config.entropyCodingMode = NV_ENC_H264_ENTROPY_CODING_MODE_CABAC;
}
-#if NVENCAPI_MAJOR_VERSION > 12 || (NVENCAPI_MAJOR_VERSION == 12 && NVENCAPI_MINOR_VERSION >= 1)
+#if NVENCAPI_MAJOR_VERSION > 12 || (NVENCAPI_MAJOR_VERSION == 12 && NVENCAPI_MINOR_VERSION >= 2)
if (api::supports_separate_bit_depth_fields(selected_api_version)) {
format_config.inputBitDepth = buffer_is_10bit() ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8;
format_config.outputBitDepth = buffer_is_10bit() ? NV_ENC_BIT_DEPTH_10 : NV_ENC_BIT_DEPTH_8;
@@ -565,7 +565,7 @@ namespace nvenc {
if (buffer_is_10bit()) {
set_hevc_10bit_format(format_config);
}
-#if NVENCAPI_MAJOR_VERSION > 12 || (NVENCAPI_MAJOR_VERSION == 12 && NVENCAPI_MINOR_VERSION >= 1)
+#if NVENCAPI_MAJOR_VERSION > 12 || (NVENCAPI_MAJOR_VERSION == 12 && NVENCAPI_MINOR_VERSION >= 2)
else if (api::supports_separate_bit_depth_fields(selected_api_version)) {
format_config.inputBitDepth = NV_ENC_BIT_DEPTH_8;
format_config.outputBitDepth = NV_ENC_BIT_DEPTH_8;
diff --git a/tests/unit/test_nvenc_api.cpp b/tests/unit/test_nvenc_api.cpp
index 4cde3bb1d9..07348697f6 100644
--- a/tests/unit/test_nvenc_api.cpp
+++ b/tests/unit/test_nvenc_api.cpp
@@ -81,10 +81,10 @@ TEST(NvencApiTest, SplitFrameSupportStartsAtSdk121) {
EXPECT_TRUE(nvenc::api::supports_implicit_split_frame(kApi13_0));
}
-TEST(NvencApiTest, SeparateBitDepthFieldsStartAtSdk121) {
+TEST(NvencApiTest, SeparateBitDepthFieldsStartAtSdk122) {
EXPECT_FALSE(nvenc::api::supports_separate_bit_depth_fields(kApi11_0));
EXPECT_FALSE(nvenc::api::supports_separate_bit_depth_fields(kApi12_0));
- EXPECT_TRUE(nvenc::api::supports_separate_bit_depth_fields(kApi12_1));
+ EXPECT_FALSE(nvenc::api::supports_separate_bit_depth_fields(kApi12_1));
EXPECT_TRUE(nvenc::api::supports_separate_bit_depth_fields(kApi12_2));
EXPECT_TRUE(nvenc::api::supports_separate_bit_depth_fields(kApi13_0));
}
From 1af84e4ad65745bbdf7c18cd8391ba159b5f82ab Mon Sep 17 00:00:00 2001
From: Chase Payne
Date: Mon, 18 May 2026 20:35:20 -0500
Subject: [PATCH 32/60] fix(stream): preserve 10-bit HDR and SDR setup
AV1 10-bit fallback was still using separate bit-depth fields when an SDK 12.2+ build negotiated NVENC API 12.1, which could leave older drivers with unset legacy bits.
RTSP setup now preserves launch HDR intent when ANNOUNCE reports SDR, while SDR 10-bit requests keep forcing HDR disabled through delayed display-helper re-applies so virtual displays do not settle in HDR/PQ.
Generated with [Codex](https://openai.com/index/introducing-gpt-5-2-codex/)
Model: GPT 5.5 Codex high
(cherry picked from commit cbf2d973858d6f9b5828bab64b0d010aae6eb748)
---
src/nvenc/nvenc_base.cpp | 20 +++++++++++++++++---
src/rtsp.cpp | 12 ++++++++----
tools/display_settings_helper.cpp | 6 +++---
3 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/src/nvenc/nvenc_base.cpp b/src/nvenc/nvenc_base.cpp
index abc331a16d..42ad05f205 100644
--- a/src/nvenc/nvenc_base.cpp
+++ b/src/nvenc/nvenc_base.cpp
@@ -525,8 +525,19 @@ namespace nvenc {
const auto set_av1_10bit_format = [&](auto &format_config) {
#if NVENCAPI_MAJOR_VERSION > 12 || (NVENCAPI_MAJOR_VERSION == 12 && NVENCAPI_MINOR_VERSION >= 2)
- format_config.inputBitDepth = NV_ENC_BIT_DEPTH_10;
- format_config.outputBitDepth = NV_ENC_BIT_DEPTH_10;
+ if (api::supports_separate_bit_depth_fields(selected_api_version)) {
+ format_config.inputBitDepth = NV_ENC_BIT_DEPTH_10;
+ format_config.outputBitDepth = NV_ENC_BIT_DEPTH_10;
+ } else {
+ // SDK 12.2 moved AV1 bit depth out of the packed bitfield, but API
+ // 12.1 drivers still read the original input/output bit-depth bits.
+#if NVENCAPI_MAJOR_VERSION > 12
+ format_config.enableTemporalSVC = 1;
+ format_config.reserved4 = 1;
+#else
+ format_config.reserved4 = 18;
+#endif
+ }
#else
format_config.inputPixelBitDepthMinus8 = 2;
format_config.pixelBitDepthMinus8 = 2;
@@ -603,10 +614,13 @@ namespace nvenc {
format_config.enableBitstreamPadding = config.insert_filler_data;
if (buffer_is_10bit()) {
set_av1_10bit_format(format_config);
- } else {
+ }
+#if NVENCAPI_MAJOR_VERSION > 12 || (NVENCAPI_MAJOR_VERSION == 12 && NVENCAPI_MINOR_VERSION >= 2)
+ else if (api::supports_separate_bit_depth_fields(selected_api_version)) {
format_config.inputBitDepth = NV_ENC_BIT_DEPTH_8;
format_config.outputBitDepth = NV_ENC_BIT_DEPTH_8;
}
+#endif
format_config.colorPrimaries = colorspace.primaries;
format_config.transferCharacteristics = colorspace.tranfer_function;
format_config.matrixCoefficients = colorspace.matrix;
diff --git a/src/rtsp.cpp b/src/rtsp.cpp
index 68814eaa2d..867fd2de66 100644
--- a/src/rtsp.cpp
+++ b/src/rtsp.cpp
@@ -1247,10 +1247,14 @@ namespace rtsp_stream {
// Prefer 10-bit SDR encoding when enabled globally or overridden per-client.
const auto client_prefer_10bit_sdr_override = nvhttp::get_client_prefer_10bit_sdr_override(session.client_uuid);
const bool prefer_10bit_sdr = client_prefer_10bit_sdr_override.value_or(config::video.prefer_10bit_sdr);
- if (prefer_10bit_sdr && !session.enable_hdr && config.monitor.dynamicRange == 0) {
- const bool hevc_main10 = config.monitor.videoFormat == 1 && video::active_hevc_mode >= 3;
- const bool av1_main10 = config.monitor.videoFormat == 2 && video::active_av1_mode >= 3;
- if (hevc_main10 || av1_main10) {
+ const bool hevc_main10 = config.monitor.videoFormat == 1 && video::active_hevc_mode >= 3;
+ const bool av1_main10 = config.monitor.videoFormat == 2 && video::active_av1_mode >= 3;
+ const bool supports_10bit_dynamic_range = hevc_main10 || av1_main10;
+ if (config.monitor.dynamicRange == 0) {
+ if (session.enable_hdr && supports_10bit_dynamic_range) {
+ BOOST_LOG(info) << "RTSP ANNOUNCE requested SDR while launch HDR is enabled; using HDR 10-bit encode";
+ config.monitor.dynamicRange = 1;
+ } else if (prefer_10bit_sdr && !session.enable_hdr && supports_10bit_dynamic_range) {
BOOST_LOG(info) << "Preferring 10-bit SDR encode for compatible client request";
config.monitor.dynamicRange = 1;
config.monitor.prefer_sdr_10bit = true;
diff --git a/tools/display_settings_helper.cpp b/tools/display_settings_helper.cpp
index e4719a191a..7ee32905fc 100644
--- a/tools/display_settings_helper.cpp
+++ b/tools/display_settings_helper.cpp
@@ -4762,10 +4762,10 @@ namespace {
constexpr int kMaxSyncVerifyAttempts = 2;
bool verified_sync = false;
std::vector reapply_delays {750ms};
- if (cfg.m_hdr_state && *cfg.m_hdr_state == display_device::HdrState::Enabled) {
- // HDR state can be (re)applied asynchronously by Windows shortly after topology/mode changes,
+ if (cfg.m_hdr_state) {
+ // HDR state can be changed asynchronously by Windows shortly after topology/mode changes,
// especially for virtual displays. Schedule a few extra best-effort re-apply attempts to
- // enforce the requested HDR state.
+ // enforce either HDR enablement or the SDR request's HDR disablement.
reapply_delays = {750ms, 2500ms, 5500ms};
}
From e2ecd6267860e91ea460be730152992fdad160a3 Mon Sep 17 00:00:00 2001
From: Chase Payne
Date: Tue, 19 May 2026 19:39:10 -0500
Subject: [PATCH 33/60] fix(display): prefer golden restore after stream end
Automatic stream-end restore could accept a stale previous-session snapshot when the current session snapshot was unavailable, leaving secondary monitors disabled.
Default restore now tries the golden snapshot before previous state and carries the golden-first setting through REVERT, matching the working hotkey path.
Generated with [Codex](https://openai.com/index/introducing-gpt-5-2-codex/)
Model: GPT 5.5 Codex xhigh
(cherry picked from commit 7968101473ab3bee58d97e9080d91c13437eb2bf)
---
.../windows/display_helper_integration.cpp | 7 +---
.../windows/display_helper_integration.h | 2 +-
.../windows/virtual_display_cleanup.cpp | 1 +
.../windows/virtual_display_cleanup.h | 2 +-
tools/display_settings_helper.cpp | 42 +++++++++++++------
5 files changed, 34 insertions(+), 20 deletions(-)
diff --git a/src/platform/windows/display_helper_integration.cpp b/src/platform/windows/display_helper_integration.cpp
index 1d22c6d38c..1e4eaa85e6 100644
--- a/src/platform/windows/display_helper_integration.cpp
+++ b/src/platform/windows/display_helper_integration.cpp
@@ -1001,12 +1001,9 @@ namespace {
}
std::string build_revert_payload(bool prefer_golden_if_current_missing) {
- if (!prefer_golden_if_current_missing) {
- return {};
- }
-
nlohmann::json j = nlohmann::json::object();
- j["sunshine_prefer_golden_if_current_missing"] = true;
+ j["sunshine_prefer_golden_if_current_missing"] = prefer_golden_if_current_missing;
+ j["sunshine_always_restore_from_golden"] = config::video.dd.always_restore_from_golden;
return j.dump();
}
diff --git a/src/platform/windows/display_helper_integration.h b/src/platform/windows/display_helper_integration.h
index 29e960ae80..4cdb7fa2da 100644
--- a/src/platform/windows/display_helper_integration.h
+++ b/src/platform/windows/display_helper_integration.h
@@ -28,7 +28,7 @@ namespace display_helper_integration {
// Launch the helper (if needed) and send REVERT.
// Returns true if the helper accepted the command; false to allow fallback.
- bool revert(bool prefer_golden_if_current_missing = false);
+ bool revert(bool prefer_golden_if_current_missing = true);
// Attempt to cancel any pending restore/revert requests on a running helper.
// Returns true if a DISARM command was sent successfully.
diff --git a/src/platform/windows/virtual_display_cleanup.cpp b/src/platform/windows/virtual_display_cleanup.cpp
index cb6ca4eb77..17fe1fd37b 100644
--- a/src/platform/windows/virtual_display_cleanup.cpp
+++ b/src/platform/windows/virtual_display_cleanup.cpp
@@ -88,6 +88,7 @@ namespace platf::virtual_display_cleanup {
<< ", enforce_db_restore=" << (enforce_db_restore ? "true" : "false")
<< ", revert_order="
<< (revert_order == revert_order_t::restore_before_remove ? "restore_before_remove" : "remove_before_restore")
+ << ", prefer_golden_if_current_missing=" << (prefer_golden_if_current_missing ? "true" : "false")
<< ")";
const bool had_active_virtual_display = has_active_virtual_display();
diff --git a/src/platform/windows/virtual_display_cleanup.h b/src/platform/windows/virtual_display_cleanup.h
index caa2c993be..6492b46c34 100644
--- a/src/platform/windows/virtual_display_cleanup.h
+++ b/src/platform/windows/virtual_display_cleanup.h
@@ -20,7 +20,7 @@ namespace platf::virtual_display_cleanup {
std::string_view reason,
bool enforce_db_restore = true,
revert_order_t revert_order = revert_order_t::remove_before_restore,
- bool prefer_golden_if_current_missing = false
+ bool prefer_golden_if_current_missing = true
);
} // namespace platf::virtual_display_cleanup
diff --git a/tools/display_settings_helper.cpp b/tools/display_settings_helper.cpp
index 7ee32905fc..bbeafea835 100644
--- a/tools/display_settings_helper.cpp
+++ b/tools/display_settings_helper.cpp
@@ -2239,7 +2239,7 @@ namespace {
// When true, prefer golden snapshot over session snapshots during restore (reduces stuck virtual screens)
std::atomic always_restore_from_golden {false};
// When true, prefer golden over previous only when current is unavailable.
- std::atomic prefer_golden_if_current_missing {false};
+ std::atomic prefer_golden_if_current_missing {true};
// Polling-based restore loop state (replaces topology-change-triggered retries)
std::jthread restore_poll_thread;
@@ -3212,9 +3212,9 @@ namespace {
return true;
}
- const bool current_snapshot_missing = !path_exists(session_current_path);
+ const bool current_snapshot_unavailable = !attempted_current;
const bool prefer_golden_before_previous =
- prefer_golden_if_current_missing.load(std::memory_order_acquire) && current_snapshot_missing;
+ prefer_golden_if_current_missing.load(std::memory_order_acquire) && current_snapshot_unavailable;
if (prefer_golden_before_previous) {
std::error_code ec_prev, ec_golden;
const bool has_previous = std::filesystem::exists(session_previous_path, ec_prev) && !ec_prev;
@@ -3348,7 +3348,7 @@ namespace {
stop_and_join(restore_poll_thread, "restore-poll");
restore_requested.store(false, std::memory_order_release);
restore_origin_epoch.store(0, std::memory_order_release);
- prefer_golden_if_current_missing.store(false, std::memory_order_release);
+ prefer_golden_if_current_missing.store(true, std::memory_order_release);
reset_pending_golden_session_fallbacks();
}
@@ -3385,7 +3385,7 @@ namespace {
void clear_restore_origin() {
restore_origin_epoch.store(0, std::memory_order_release);
- prefer_golden_if_current_missing.store(false, std::memory_order_release);
+ prefer_golden_if_current_missing.store(true, std::memory_order_release);
reset_pending_golden_session_fallbacks();
}
@@ -4554,23 +4554,36 @@ namespace {
}
}
- bool parse_revert_prefer_golden_payload(std::span payload) {
+ struct RevertOptions {
+ bool prefer_golden_if_current_missing {true};
+ std::optional always_restore_from_golden;
+ };
+
+ RevertOptions parse_revert_payload(std::span payload) {
+ RevertOptions options;
if (payload.empty()) {
- return false;
+ return options;
}
try {
std::string raw(reinterpret_cast(payload.data()), payload.size());
auto j = nlohmann::json::parse(raw, nullptr, false);
if (!j.is_object()) {
- return false;
+ return options;
}
auto it = j.find("sunshine_prefer_golden_if_current_missing");
- return it != j.end() && it->is_boolean() && it->get();
+ if (it != j.end() && it->is_boolean()) {
+ options.prefer_golden_if_current_missing = it->get();
+ }
+
+ it = j.find("sunshine_always_restore_from_golden");
+ if (it != j.end() && it->is_boolean()) {
+ options.always_restore_from_golden = it->get();
+ }
} catch (...) {
- return false;
}
+ return options;
}
/**
@@ -4808,16 +4821,19 @@ namespace {
}
void handle_revert(ServiceState &state, std::atomic &running, std::span payload) {
- const bool prefer_golden_if_current_missing = parse_revert_prefer_golden_payload(payload);
+ const auto revert_options = parse_revert_payload(payload);
BOOST_LOG(info) << "REVERT command received - initiating display settings restoration"
- << (prefer_golden_if_current_missing ? " (prefer golden if current missing)." : ".");
+ << (revert_options.prefer_golden_if_current_missing ? " (prefer golden if current missing)." : ".");
state.retry_apply_on_topology.store(false, std::memory_order_release);
state.cancel_delayed_reapply();
state.cancel_post_apply_tasks();
state.direct_revert_bypass_grace.store(true, std::memory_order_release);
state.exit_after_revert.store(true, std::memory_order_release);
state.restore_requested.store(true, std::memory_order_release);
- state.prefer_golden_if_current_missing.store(prefer_golden_if_current_missing, std::memory_order_release);
+ if (revert_options.always_restore_from_golden.has_value()) {
+ state.always_restore_from_golden.store(*revert_options.always_restore_from_golden, std::memory_order_release);
+ }
+ state.prefer_golden_if_current_missing.store(revert_options.prefer_golden_if_current_missing, std::memory_order_release);
state.restore_origin_epoch.store(state.current_connection_epoch(), std::memory_order_release);
// Give Sunshine a short window to immediately start a new session and DISARM,
From 52d010d8eff1fc9b25af1cabdba125e563db904d Mon Sep 17 00:00:00 2001
From: Chase Payne
Date: Wed, 20 May 2026 10:34:09 -0500
Subject: [PATCH 34/60] fix(display): validate snapshots and output overrides
Golden snapshots could appear current after monitor, mode, HDR, primary, or layout changes, leaving recovery decisions based on stale state.
Expose snapshot freshness through the config API and show a dashboard warning when the saved display snapshot should be recreated.
Keep physical output overrides as capture targets when display configuration is disabled, preserve runtime override selection, and cache elevated embedded MSI payloads where Windows Installer can read them.
Generated with [Codex](https://openai.com/codex/)
Model: GPT 5.5 high
(cherry picked from commit 91a96809eb238d02ef68e4b08054b85c6d9f1e39)
---
.../bootstrapper/VibeshineInstaller.cs | 73 +++-
src/confighttp.cpp | 327 +++++++++++++++++-
.../display_helper_request_helpers.cpp | 27 +-
src/video.cpp | 22 ++
.../assets/web/public/assets/locale/en.json | 3 +
.../web/public/assets/locale/en_GB.json | 3 +
.../web/public/assets/locale/en_US.json | 3 +
.../common/assets/web/views/DashboardView.vue | 23 +-
.../test_display_helper_session_deferral.cpp | 13 +
9 files changed, 475 insertions(+), 19 deletions(-)
diff --git a/packaging/windows/bootstrapper/VibeshineInstaller.cs b/packaging/windows/bootstrapper/VibeshineInstaller.cs
index 574dac56e5..f63fac4b6e 100644
--- a/packaging/windows/bootstrapper/VibeshineInstaller.cs
+++ b/packaging/windows/bootstrapper/VibeshineInstaller.cs
@@ -3411,12 +3411,15 @@ private static bool IsInstallerPayloadPath(string msiPath) {
}
try {
- var fullPath = Path.GetFullPath(msiPath);
- var tempRoot = Path.GetFullPath(Path.Combine(Path.GetTempPath(), ProductIdentity.TempRootName));
- return fullPath.StartsWith(tempRoot, StringComparison.OrdinalIgnoreCase);
+ foreach (var root in GetEmbeddedMsiExtractRoots()) {
+ if (PathIsUnderDirectory(msiPath, root)) {
+ return true;
+ }
+ }
} catch {
- return false;
}
+
+ return false;
}
private static bool LogShowsMsiAccessFailure(string logPath, string msiPath) {
@@ -4332,6 +4335,12 @@ public static InstallerResult RunCli(InstallerArguments arguments) {
string injectedMsiPath = null;
var recoveryDetails = new List();
+ if (!IsProcessElevated()
+ && string.IsNullOrWhiteSpace(arguments.MsiPathOverride)
+ && ShouldElevateCliForEmbeddedPayload(cliArgs, hasOperation)) {
+ return RunElevatedBootstrapperCli(arguments);
+ }
+
if (!hasOperation) {
installMsiPath = ResolveMsiPath(arguments.MsiPathOverride);
injectedMsiPath = installMsiPath;
@@ -4793,6 +4802,32 @@ private static bool IsServiceRunning(string serviceName) {
}
}
+ private static bool ShouldElevateCliForEmbeddedPayload(IReadOnlyList cliArgs, bool hasOperation) {
+ if (!hasOperation) {
+ return true;
+ }
+ if (cliArgs == null) {
+ return false;
+ }
+
+ for (var index = 0; index < cliArgs.Count; index++) {
+ var operation = cliArgs[index];
+ if (!IsOperationSwitch(operation)) {
+ continue;
+ }
+ if (!string.Equals(operation, "/i", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(operation, "/package", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(operation, "/a", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(operation, "/x", StringComparison.OrdinalIgnoreCase)) {
+ return false;
+ }
+
+ return index + 1 >= cliArgs.Count || LooksLikeSwitch(cliArgs[index + 1]);
+ }
+
+ return false;
+ }
+
private static string BuildCompetingProductUninstallFailureMessage(string uninstallMessage) {
var prefix = "Failed to uninstall Apollo, Nimbus, Vibepollo, or Sunshine before starting Nimbus installation.";
if (string.IsNullOrWhiteSpace(uninstallMessage)) {
@@ -5303,10 +5338,7 @@ private static string ExtractEmbeddedMsi(bool forceFreshExtract = false) {
}
private static string BuildEmbeddedMsiExtractDirectory(string versionToken, bool forceFreshExtract) {
- var root = Path.Combine(
- Path.GetTempPath(),
- ProductIdentity.TempRootName,
- versionToken);
+ var root = Path.Combine(GetEmbeddedMsiExtractRoot(), versionToken);
if (!forceFreshExtract) {
return root;
}
@@ -5314,6 +5346,31 @@ private static string BuildEmbeddedMsiExtractDirectory(string versionToken, bool
return Path.Combine(root, "recovery_" + Guid.NewGuid().ToString("N"));
}
+ private static string GetEmbeddedMsiExtractRoot() {
+ // Windows Installer may run in the service context and fail to read per-user temp payloads.
+ if (IsProcessElevated()) {
+ var programData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
+ if (!string.IsNullOrWhiteSpace(programData)) {
+ return Path.Combine(programData, "Nimbus", "InstallerCache");
+ }
+ }
+
+ return Path.Combine(Path.GetTempPath(), ProductIdentity.TempRootName);
+ }
+
+ private static IEnumerable GetEmbeddedMsiExtractRoots() {
+ var roots = new List {
+ Path.Combine(Path.GetTempPath(), ProductIdentity.TempRootName)
+ };
+
+ var programData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
+ if (!string.IsNullOrWhiteSpace(programData)) {
+ roots.Add(Path.Combine(programData, "Nimbus", "InstallerCache"));
+ }
+
+ return roots;
+ }
+
private static void WriteStreamAtomically(Stream input, string destinationPath) {
if (input == null) {
throw new InvalidOperationException("The embedded MSI payload could not be read.");
diff --git a/src/confighttp.cpp b/src/confighttp.cpp
index b601256e58..9f851d62ad 100644
--- a/src/confighttp.cpp
+++ b/src/confighttp.cpp
@@ -13,8 +13,8 @@
#include
#include
#include
-#include
#include
+#include
#include
#include
#include
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
// lib includes
#include
@@ -3791,6 +3792,102 @@ namespace confighttp {
constexpr int kGoldenSnapshotLatestVersion = 2;
+ struct golden_current_mode_t {
+ unsigned int width {};
+ unsigned int height {};
+ double refresh_hz {};
+ };
+
+ struct golden_current_summary_t {
+ bool valid {false};
+ bool active_virtual_display {false};
+ std::set devices;
+ std::unordered_map modes;
+ std::unordered_map hdr;
+ std::unordered_map> origins;
+ std::string primary;
+ };
+
+ static std::string normalized_display_id(std::string id) {
+ id.erase(id.begin(), std::find_if(id.begin(), id.end(), [](unsigned char ch) {
+ return !std::isspace(ch);
+ }));
+ id.erase(std::find_if(id.rbegin(), id.rend(), [](unsigned char ch) {
+ return !std::isspace(ch);
+ }).base(),
+ id.end());
+ std::transform(id.begin(), id.end(), id.begin(), [](unsigned char ch) {
+ return static_cast(std::tolower(ch));
+ });
+ return id;
+ }
+
+ static bool contains_ci(const std::string &haystack, const std::string &needle) {
+ if (needle.empty()) {
+ return true;
+ }
+ if (haystack.size() < needle.size()) {
+ return false;
+ }
+ for (size_t i = 0; i + needle.size() <= haystack.size(); ++i) {
+ bool match = true;
+ for (size_t j = 0; j < needle.size(); ++j) {
+ if (std::tolower(static_cast(haystack[i + j])) !=
+ std::tolower(static_cast(needle[j]))) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static bool equals_ci(const std::string &lhs, const std::string &rhs) {
+ return lhs.size() == rhs.size() && contains_ci(lhs, rhs);
+ }
+
+ static bool is_virtual_display_device(const display_device::EnumeratedDevice &device) {
+ if (contains_ci(device.m_device_id, "SUDOVDA") ||
+ contains_ci(device.m_device_id, "SUDOMAKER") ||
+ contains_ci(device.m_display_name, "SUDOVDA") ||
+ contains_ci(device.m_display_name, "SUDOMAKER") ||
+ contains_ci(device.m_friendly_name, "SUDOVDA") ||
+ contains_ci(device.m_friendly_name, "SUDOMAKER")) {
+ return true;
+ }
+ if (equals_ci(device.m_friendly_name, "SudoMaker Virtual Display Adapter")) {
+ return true;
+ }
+ return device.m_edid && equals_ci(device.m_edid->m_manufacturer_id, "SMK");
+ }
+
+ static bool is_active_display_device(const display_device::EnumeratedDevice &device) {
+ return device.m_info.has_value() || !device.m_display_name.empty();
+ }
+
+ static std::optional floating_to_double(const display_device::FloatingPoint &value) {
+ if (std::holds_alternative(value)) {
+ return std::get(value);
+ }
+ const auto &rat = std::get(value);
+ if (rat.m_denominator == 0) {
+ return std::nullopt;
+ }
+ return static_cast(rat.m_numerator) / static_cast(rat.m_denominator);
+ }
+
+ static bool nearly_equal_refresh(double lhs, double rhs) {
+ if (!std::isfinite(lhs) || !std::isfinite(rhs)) {
+ return false;
+ }
+ const double diff = std::abs(lhs - rhs);
+ const double scale = std::max({1.0, std::abs(lhs), std::abs(rhs)});
+ return diff <= scale * 1e-4;
+ }
+
static std::optional read_json_file_nofail(const std::filesystem::path &path) {
try {
std::ifstream file(path, std::ios::binary);
@@ -3840,6 +3937,213 @@ namespace confighttp {
return false;
}
+ static std::set snapshot_topology_devices(const nlohmann::json &root) {
+ std::set ids;
+ auto topology = root.find("topology");
+ if (topology != root.end() && topology->is_array()) {
+ for (const auto &group : *topology) {
+ if (!group.is_array()) {
+ continue;
+ }
+ for (const auto &device : group) {
+ if (device.is_string()) {
+ auto id = normalized_display_id(device.get());
+ if (!id.empty()) {
+ ids.insert(std::move(id));
+ }
+ }
+ }
+ }
+ }
+ if (ids.empty()) {
+ auto modes = root.find("modes");
+ if (modes != root.end() && modes->is_object()) {
+ for (auto it = modes->begin(); it != modes->end(); ++it) {
+ auto id = normalized_display_id(it.key());
+ if (!id.empty()) {
+ ids.insert(std::move(id));
+ }
+ }
+ }
+ }
+ return ids;
+ }
+
+ static std::unordered_map snapshot_modes(const nlohmann::json &root) {
+ std::unordered_map modes;
+ auto modes_it = root.find("modes");
+ if (modes_it == root.end() || !modes_it->is_object()) {
+ return modes;
+ }
+ for (auto it = modes_it->begin(); it != modes_it->end(); ++it) {
+ if (!it->is_object()) {
+ continue;
+ }
+ auto id = normalized_display_id(it.key());
+ const auto width = it->value("w", 0u);
+ const auto height = it->value("h", 0u);
+ const auto num = it->value("num", 0u);
+ const auto den = it->value("den", 0u);
+ if (id.empty() || width == 0 || height == 0 || den == 0) {
+ continue;
+ }
+ modes.emplace(std::move(id), golden_current_mode_t {
+ .width = width,
+ .height = height,
+ .refresh_hz = static_cast(num) / static_cast(den),
+ });
+ }
+ return modes;
+ }
+
+ static std::unordered_map snapshot_hdr_states(const nlohmann::json &root) {
+ std::unordered_map states;
+ auto hdr_it = root.find("hdr");
+ if (hdr_it == root.end() || !hdr_it->is_object()) {
+ return states;
+ }
+ for (auto it = hdr_it->begin(); it != hdr_it->end(); ++it) {
+ if (!it->is_string()) {
+ continue;
+ }
+ auto id = normalized_display_id(it.key());
+ auto value = boost::algorithm::to_lower_copy(it->get());
+ if (id.empty() || (value != "on" && value != "off")) {
+ continue;
+ }
+ states.emplace(std::move(id), value == "on");
+ }
+ return states;
+ }
+
+ static std::unordered_map> snapshot_origins(const nlohmann::json &root) {
+ std::unordered_map> origins;
+ auto origins_it = root.find("origins");
+ if (origins_it == root.end() || !origins_it->is_object()) {
+ return origins;
+ }
+ for (auto it = origins_it->begin(); it != origins_it->end(); ++it) {
+ if (!it->is_object()) {
+ continue;
+ }
+ auto id = normalized_display_id(it.key());
+ if (id.empty()) {
+ continue;
+ }
+ origins.emplace(std::move(id), std::make_pair(it->value("x", 0), it->value("y", 0)));
+ }
+ return origins;
+ }
+
+ static golden_current_summary_t current_golden_comparison_summary() {
+ golden_current_summary_t summary;
+ const auto devices = display_helper_integration::enumerate_devices(display_device::DeviceEnumerationDetail::Full);
+ if (!devices) {
+ return summary;
+ }
+
+ std::set exclusions;
+ for (auto id : config::video.dd.snapshot_exclude_devices) {
+ id = normalized_display_id(std::move(id));
+ if (!id.empty()) {
+ exclusions.insert(std::move(id));
+ }
+ }
+
+ for (const auto &device : *devices) {
+ if (is_virtual_display_device(device)) {
+ if (is_active_display_device(device)) {
+ summary.active_virtual_display = true;
+ }
+ continue;
+ }
+ if (!device.m_info || device.m_display_name.empty()) {
+ continue;
+ }
+
+ auto id = normalized_display_id(device.m_device_id.empty() ? device.m_display_name : device.m_device_id);
+ if (id.empty() || exclusions.contains(id)) {
+ continue;
+ }
+
+ summary.devices.insert(id);
+ if (auto refresh = floating_to_double(device.m_info->m_refresh_rate)) {
+ summary.modes[id] = golden_current_mode_t {
+ .width = device.m_info->m_resolution.m_width,
+ .height = device.m_info->m_resolution.m_height,
+ .refresh_hz = *refresh,
+ };
+ }
+ if (device.m_info->m_hdr_state) {
+ summary.hdr[id] = *device.m_info->m_hdr_state == display_device::HdrState::Enabled;
+ }
+ summary.origins[id] = std::make_pair(device.m_info->m_origin_point.m_x, device.m_info->m_origin_point.m_y);
+ if (device.m_info->m_primary) {
+ summary.primary = id;
+ }
+ }
+
+ summary.valid = !summary.devices.empty();
+ return summary;
+ }
+
+ static std::optional snapshot_current_mismatch_reason(const nlohmann::json &root) {
+ const auto current = current_golden_comparison_summary();
+ if (current.active_virtual_display) {
+ return std::nullopt;
+ }
+ if (!current.valid) {
+ return std::nullopt;
+ }
+
+ const auto snapshot_devices = snapshot_topology_devices(root);
+ if (snapshot_devices.empty()) {
+ return "invalid_snapshot";
+ }
+ if (snapshot_devices != current.devices) {
+ return "display_set_changed";
+ }
+
+ const auto modes = snapshot_modes(root);
+ for (const auto &[id, mode] : modes) {
+ auto current_mode = current.modes.find(id);
+ if (current_mode == current.modes.end()) {
+ continue;
+ }
+ if (mode.width != current_mode->second.width ||
+ mode.height != current_mode->second.height ||
+ !nearly_equal_refresh(mode.refresh_hz, current_mode->second.refresh_hz)) {
+ return "display_mode_changed";
+ }
+ }
+
+ const auto hdr_states = snapshot_hdr_states(root);
+ for (const auto &[id, hdr] : hdr_states) {
+ auto current_hdr = current.hdr.find(id);
+ if (current_hdr != current.hdr.end() && hdr != current_hdr->second) {
+ return "hdr_changed";
+ }
+ }
+
+ auto primary_it = root.find("primary");
+ if (primary_it != root.end() && primary_it->is_string()) {
+ const auto primary = normalized_display_id(primary_it->get());
+ if (!primary.empty() && !current.primary.empty() && primary != current.primary) {
+ return "primary_changed";
+ }
+ }
+
+ const auto origins = snapshot_origins(root);
+ for (const auto &[id, origin] : origins) {
+ auto current_origin = current.origins.find(id);
+ if (current_origin != current.origins.end() && origin != current_origin->second) {
+ return "layout_changed";
+ }
+ }
+
+ return "";
+ }
+
void getGoldenStatus(resp_https_t response, req_https_t request) {
if (!authenticate(response, request)) {
return;
@@ -3850,6 +4154,9 @@ namespace confighttp {
std::optional snapshot_version;
bool has_layout = false;
bool needs_layout_upgrade = false;
+ bool out_of_date = false;
+ bool comparison_available = false;
+ std::string out_of_date_reason;
try {
for (const auto &p : golden_snapshot_candidates()) {
if (file_exists_nofail(p)) {
@@ -3859,8 +4166,23 @@ namespace confighttp {
has_layout = snapshot_has_layout_data(*root);
const bool latest_schema = snapshot_version && *snapshot_version >= kGoldenSnapshotLatestVersion;
needs_layout_upgrade = !latest_schema || !has_layout;
+ out_of_date = needs_layout_upgrade;
+ if (needs_layout_upgrade) {
+ out_of_date_reason = "schema_upgrade_required";
+ }
+ if (!has_active_stream_sessions()) {
+ if (auto mismatch = snapshot_current_mismatch_reason(*root)) {
+ comparison_available = true;
+ if (!mismatch->empty()) {
+ out_of_date = true;
+ out_of_date_reason = *mismatch;
+ }
+ }
+ }
} else {
needs_layout_upgrade = true;
+ out_of_date = true;
+ out_of_date_reason = "unreadable_snapshot";
}
break;
}
@@ -3872,6 +4194,9 @@ namespace confighttp {
out["latest_snapshot_version"] = kGoldenSnapshotLatestVersion;
out["has_layout"] = has_layout;
out["needs_layout_upgrade"] = needs_layout_upgrade;
+ out["out_of_date"] = out_of_date;
+ out["comparison_available"] = comparison_available;
+ out["out_of_date_reason"] = out_of_date_reason;
send_response(response, out);
}
diff --git a/src/platform/windows/display_helper_request_helpers.cpp b/src/platform/windows/display_helper_request_helpers.cpp
index c0f7aa0800..9327a53bfe 100644
--- a/src/platform/windows/display_helper_request_helpers.cpp
+++ b/src/platform/windows/display_helper_request_helpers.cpp
@@ -8,6 +8,7 @@
#include "src/display_device.h"
#include "src/globals.h"
+ #include "src/logging.h"
#include "src/platform/common.h"
#include "src/platform/windows/display_helper_coordinator.h"
#include "src/platform/windows/frame_limiter_nvcp.h"
@@ -78,6 +79,17 @@ namespace display_helper_integration::helpers {
return it->cmd.empty() && it->playnite_id.empty();
}
+ bool output_name_targets_virtual(const std::string &output_name) {
+ return boost::iequals(output_name, VDISPLAY::SUDOVDA_VIRTUAL_DISPLAY_SELECTION) ||
+ VDISPLAY::is_virtual_display_output(output_name);
+ }
+
+ bool session_has_physical_output_override(const rtsp_stream::launch_session_t &session) {
+ return session.output_name_override &&
+ !session.output_name_override->empty() &&
+ !output_name_targets_virtual(*session.output_name_override);
+ }
+
rtsp_stream::launch_session_t make_display_request_session_snapshot_impl(const rtsp_stream::launch_session_t &session) {
rtsp_stream::launch_session_t snapshot {};
snapshot.id = session.id;
@@ -217,7 +229,8 @@ namespace display_helper_integration::helpers {
effective_video_config_.output_name = *runtime_output_override;
}
}
- if (effective_video_config_.dd.configuration_option == config::video_t::dd_t::config_option_e::disabled &&
+ if (session_.virtual_display &&
+ effective_video_config_.dd.configuration_option == config::video_t::dd_t::config_option_e::disabled &&
!effective_video_config_.output_name.empty()) {
effective_video_config_.dd.configuration_option = config::video_t::dd_t::config_option_e::ensure_active;
}
@@ -459,7 +472,8 @@ namespace display_helper_integration::helpers {
effective_video_config_.output_name = *runtime_output_override;
}
}
- if (effective_video_config_.dd.configuration_option == config::video_t::dd_t::config_option_e::disabled &&
+ if (session_.virtual_display &&
+ effective_video_config_.dd.configuration_option == config::video_t::dd_t::config_option_e::disabled &&
!effective_video_config_.output_name.empty()) {
effective_video_config_.dd.configuration_option = config::video_t::dd_t::config_option_e::ensure_active;
}
@@ -664,6 +678,15 @@ namespace display_helper_integration::helpers {
}
std::optional build_request_from_session(const config::video_t &video_config, const rtsp_stream::launch_session_t &session) {
+ const auto effective_config_option =
+ session.dd_config_option_override.value_or(video_config.dd.configuration_option);
+ if (!session.virtual_display &&
+ session_has_physical_output_override(session) &&
+ effective_config_option == config::video_t::dd_t::config_option_e::disabled) {
+ BOOST_LOG(info) << "Display helper: physical output override with display configuration disabled; using capture target only.";
+ return std::nullopt;
+ }
+
DisplayApplyBuilder builder;
SessionDisplayConfigurationHelper config_helper(video_config, session);
if (!config_helper.configure(builder)) {
diff --git a/src/video.cpp b/src/video.cpp
index 674fe0e50d..9d75fbef54 100644
--- a/src/video.cpp
+++ b/src/video.cpp
@@ -75,6 +75,13 @@ namespace video {
return false;
}
+ if (auto runtime_output_name = config::runtime_output_name_override()) {
+ if (!runtime_output_name->empty()) {
+ return boost::iequals(*runtime_output_name, VDISPLAY::SUDOVDA_VIRTUAL_DISPLAY_SELECTION) ||
+ VDISPLAY::is_virtual_display_output(*runtime_output_name);
+ }
+ }
+
if (!VDISPLAY::isSudaVDADriverInstalled()) {
return false;
}
@@ -1379,6 +1386,8 @@ namespace video {
*/
void refresh_displays(platf::mem_type_e dev_type, std::vector &display_names, int ¤t_display_index, std::string &preferred_display_name) {
// It is possible that the output name may be empty even if it wasn't before (device disconnected) or vice-versa
+ const auto runtime_output_override = config::runtime_output_name_override();
+ const bool has_runtime_output_override = runtime_output_override && !runtime_output_override->empty();
const auto output_name = display_device::map_output_name(config::get_active_output_name());
std::string current_display_name;
auto names_match = [](const std::string &lhs, const std::string &rhs) {
@@ -1425,6 +1434,19 @@ namespace video {
// We now have a new display name list, so reset the index back to 0
current_display_index = 0;
+ if (has_runtime_output_override && !output_name.empty()) {
+ for (int x = 0; x < display_names.size(); ++x) {
+ if (names_match(display_names[x], output_name)) {
+ current_display_index = x;
+ return;
+ }
+ }
+
+ BOOST_LOG(warning) << "Runtime display override [" << *runtime_output_override
+ << "] mapped to [" << output_name
+ << "] but was not found in the capture display list";
+ }
+
if (current_display_name.empty()) {
current_display_name = display_device::map_output_name(config::video.output_name);
}
diff --git a/src_assets/common/assets/web/public/assets/locale/en.json b/src_assets/common/assets/web/public/assets/locale/en.json
index eb17e5b207..385b25cf5a 100644
--- a/src_assets/common/assets/web/public/assets/locale/en.json
+++ b/src_assets/common/assets/web/public/assets/locale/en.json
@@ -229,6 +229,9 @@
"golden_layout_upgrade_title": "Golden display snapshot needs an update",
"golden_layout_upgrade_desc": "Your saved snapshot predates display layout support. Recreate it to restore portrait and landscape monitor layouts correctly.",
"golden_layout_upgrade_action": "Open Display Settings",
+ "golden_snapshot_outdated_title": "Display snapshot may be out of date",
+ "golden_snapshot_outdated_desc": "Your saved snapshot may no longer match your display setup. Recreate it when possible to reduce the chance of display recovery issues.",
+ "golden_snapshot_outdated_action": "Open Display Settings",
"dd_snapshot_restore_hotkey": "Restore snapshot hotkey",
"dd_snapshot_restore_hotkey_desc": "Windows-only global hotkey. Useful for forcing virtual displays off and restoring snapshots when Nimbus is paused or stuck. Click the field and press the combo you want.",
"dd_snapshot_restore_hotkey_capture": "Listening... press a combo now.",
diff --git a/src_assets/common/assets/web/public/assets/locale/en_GB.json b/src_assets/common/assets/web/public/assets/locale/en_GB.json
index 16dca4e3ba..31691b81f6 100644
--- a/src_assets/common/assets/web/public/assets/locale/en_GB.json
+++ b/src_assets/common/assets/web/public/assets/locale/en_GB.json
@@ -210,6 +210,9 @@
"golden_layout_upgrade_title": "Golden display snapshot needs an update",
"golden_layout_upgrade_desc": "Your saved snapshot predates display layout support. Recreate it to restore portrait and landscape monitor layouts correctly.",
"golden_layout_upgrade_action": "Open Display Settings",
+ "golden_snapshot_outdated_title": "Display snapshot may be out of date",
+ "golden_snapshot_outdated_desc": "Your saved snapshot may no longer match your display setup. Recreate it when possible to reduce the chance of display recovery issues.",
+ "golden_snapshot_outdated_action": "Open Display Settings",
"dd_config_verify_only": "Verify that the display is enabled (default)",
"dd_hdr_option": "HDR",
"dd_hdr_option_auto": "Switch on/off the HDR mode as requested by the client (default)",
diff --git a/src_assets/common/assets/web/public/assets/locale/en_US.json b/src_assets/common/assets/web/public/assets/locale/en_US.json
index 3a9f3993b2..b8d356d5e1 100644
--- a/src_assets/common/assets/web/public/assets/locale/en_US.json
+++ b/src_assets/common/assets/web/public/assets/locale/en_US.json
@@ -214,6 +214,9 @@
"golden_layout_upgrade_title": "Golden display snapshot needs an update",
"golden_layout_upgrade_desc": "Your saved snapshot predates display layout support. Recreate it to restore portrait and landscape monitor layouts correctly.",
"golden_layout_upgrade_action": "Open Display Settings",
+ "golden_snapshot_outdated_title": "Display snapshot may be out of date",
+ "golden_snapshot_outdated_desc": "Your saved snapshot may no longer match your display setup. Recreate it when possible to reduce the chance of display recovery issues.",
+ "golden_snapshot_outdated_action": "Open Display Settings",
"dd_config_verify_only": "Verify that the display is enabled (default)",
"dd_hdr_option": "HDR",
"dd_hdr_option_auto": "Switch on/off the HDR mode as requested by the client (default)",
diff --git a/src_assets/common/assets/web/views/DashboardView.vue b/src_assets/common/assets/web/views/DashboardView.vue
index 8dc040d6bb..1f634b3bf9 100644
--- a/src_assets/common/assets/web/views/DashboardView.vue
+++ b/src_assets/common/assets/web/views/DashboardView.vue
@@ -223,7 +223,7 @@
{{
translate(
- 'config.golden_layout_upgrade_title',
- 'Golden display snapshot needs an update',
+ 'config.golden_snapshot_outdated_title',
+ 'Display snapshot may be out of date',
)
}}
{{
translate(
- 'config.golden_layout_upgrade_desc',
- 'Your saved snapshot predates display layout support. Recreate it to restore portrait and landscape monitor layouts correctly.',
+ 'config.golden_snapshot_outdated_desc',
+ 'Your saved snapshot may no longer match your display setup. Recreate it when possible to reduce the chance of display recovery issues.',
)
}}
@@ -268,7 +268,7 @@
>
{{
- translate('config.golden_layout_upgrade_action', 'Open Display Settings')
+ translate('config.golden_snapshot_outdated_action', 'Open Display Settings')
}}
@@ -535,6 +535,9 @@ type GoldenStatus = {
latest_snapshot_version?: number;
has_layout?: boolean;
needs_layout_upgrade?: boolean;
+ out_of_date?: boolean;
+ comparison_available?: boolean;
+ out_of_date_reason?: string;
};
const playnite = ref(null);
@@ -1023,10 +1026,14 @@ const showVigemBanner = computed(() => {
return plat === 'windows' && controllerEnabled && vigemInstalled.value === false;
});
-const showGoldenLayoutUpgradeBanner = computed(() => {
+const showGoldenSnapshotOutOfDateBanner = computed(() => {
const plat = (configStore.metadata?.platform || '').toLowerCase();
if (plat !== 'windows') return false;
- return goldenStatus.value?.exists === true && goldenStatus.value?.needs_layout_upgrade === true;
+ return (
+ goldenStatus.value?.exists === true &&
+ (goldenStatus.value?.needs_layout_upgrade === true ||
+ goldenStatus.value?.out_of_date === true)
+ );
});
const playniteUpdateAvailable = computed(() => {
diff --git a/tests/unit/test_display_helper_session_deferral.cpp b/tests/unit/test_display_helper_session_deferral.cpp
index 7d8b226c0a..0d13e6b787 100644
--- a/tests/unit/test_display_helper_session_deferral.cpp
+++ b/tests/unit/test_display_helper_session_deferral.cpp
@@ -3,6 +3,7 @@
* @brief Unit tests for Sunshine display helper session deferral.
*/
#include "../tests_common.h"
+#include "src/platform/windows/display_helper_request_helpers.h"
#include "src/platform/windows/display_helper_session_deferral.h"
#include "src/rtsp.h"
@@ -114,3 +115,15 @@ TEST(DisplayHelperSessionDeferral, ReschedulesAndDropsForNewerPending) {
reschedule = manager.reschedule(*result.pending);
EXPECT_TRUE(reschedule.dropped_for_newer);
}
+
+TEST(DisplayHelperRequestHelpers, SkipsPhysicalOutputWhenDisplayConfigurationDisabled) {
+ config::video_t video_config {};
+ video_config.dd.configuration_option = config::video_t::dd_t::config_option_e::disabled;
+
+ rtsp_stream::launch_session_t session {};
+ session.output_name_override = "{physical-monitor-guid}";
+
+ auto request = display_helper_integration::helpers::build_request_from_session(video_config, session);
+
+ EXPECT_FALSE(request.has_value());
+}
From 40ef134ba8818faaaa26af67653de82a3f504cbe Mon Sep 17 00:00:00 2001
From: Chase Payne
Date: Sat, 25 Apr 2026 14:58:33 -0500
Subject: [PATCH 35/60] fix(display-helper): preserve unconfirmed restores
across reconnect
Keep virtual-display stream startup probes from cancelling or overwriting an
in-flight physical display restore. When a restore has already begun, skip
current-session snapshot refreshes, ignore late DISARM probes, and keep the
existing helper alive so an explicit APPLY can supersede the restore through
IPC instead of hard-restarting the process.
This prevents degraded physical monitor states from replacing the restore
baseline while the helper is still waiting for the golden or previous layout
to confirm after the monitor becomes available again.
Generated with [Codex](https://openai.com/index/introducing-gpt-5-3-codex/)
Model: GPT-5.5 X-High
(cherry picked from commit 72b0d996d91aa0e3230111ca8774e350e6aee355)
---
.../windows/display_helper_integration.cpp | 65 +++++++++++++++----
tools/display_settings_helper.cpp | 23 ++++++-
2 files changed, 76 insertions(+), 12 deletions(-)
diff --git a/src/platform/windows/display_helper_integration.cpp b/src/platform/windows/display_helper_integration.cpp
index 1e4eaa85e6..1e22e4276c 100644
--- a/src/platform/windows/display_helper_integration.cpp
+++ b/src/platform/windows/display_helper_integration.cpp
@@ -203,9 +203,13 @@ namespace {
constexpr std::chrono::milliseconds kHelperIpcReadyTimeout {5000};
constexpr std::chrono::milliseconds kHelperIpcReadyPoll {100};
- // Stream-start requirement: stop any helper restore activity immediately.
+ // Stream-start requirement: stop very recent helper restore activity quickly.
+ // Once the helper has had time to begin an actual restore, do not kill/overwrite
+ // that in-flight restore from a later stream-start probe; the helper will either
+ // finish restoring or an explicit APPLY will supersede it.
constexpr std::chrono::milliseconds kDisarmRestoreBudget {150};
constexpr std::chrono::milliseconds kDisarmRetryThrottle {150};
+ constexpr std::chrono::milliseconds kDisarmRestoreGrace {5000};
constexpr std::chrono::milliseconds kDeferredApplyInitialDelay {2000};
constexpr std::chrono::milliseconds kDeferredApplyRetryBase {500};
constexpr std::chrono::milliseconds kDeferredApplyRetryMax {10000};
@@ -215,6 +219,16 @@ namespace {
bool ensure_helper_started(bool force_restart = false, bool force_enable = false);
const char *virtual_layout_to_string(const display_helper_integration::VirtualDisplayArrangement layout);
+ bool helper_process_running() {
+ std::lock_guard lg(helper_mutex());
+ if (HANDLE h = helper_proc().get_process_handle()) {
+ return WaitForSingleObject(h, 0) == WAIT_TIMEOUT;
+ }
+ return false;
+ }
+
+ bool restore_expected_with_live_helper();
+
std::chrono::milliseconds deferred_apply_retry_delay(int attempts) {
if (attempts <= 0) {
return kDeferredApplyRetryBase;
@@ -586,6 +600,17 @@ namespace {
return duration_cast(steady_clock::now().time_since_epoch()).count();
}
+ bool restore_expected_with_live_helper() {
+ if (!g_restore_expected.load(std::memory_order_relaxed)) {
+ return false;
+ }
+ if (helper_process_running()) {
+ return true;
+ }
+ g_restore_expected.store(false, std::memory_order_relaxed);
+ return false;
+ }
+
// Active session display parameters snapshot for re-apply on reconnect.
// We do NOT cache serialized JSON, only the subset of session fields that
// affect display configuration. On reconnect, we rebuild the full
@@ -625,20 +650,25 @@ namespace {
return false;
}
- bool helper_running = false;
- {
- std::lock_guard lg(helper_mutex());
- if (HANDLE h = helper_proc().get_process_handle()) {
- helper_running = (WaitForSingleObject(h, 0) == WAIT_TIMEOUT);
- }
- }
-
+ const bool helper_running = helper_process_running();
if (!helper_running) {
+ g_restore_expected.store(false, std::memory_order_relaxed);
return false;
}
const bool restore_expected = g_restore_expected.load(std::memory_order_relaxed);
const auto now_us = now_steady_us();
+ const auto last_revert_us = g_last_revert_us.load(std::memory_order_relaxed);
+ if (restore_expected && last_revert_us > 0) {
+ const auto disarm_grace_us = kDisarmRestoreGrace.count() * 1000LL;
+ if ((now_us - last_revert_us) >= disarm_grace_us) {
+ BOOST_LOG(info) << "Display helper: restore has been pending for more than "
+ << kDisarmRestoreGrace.count()
+ << "ms; not sending DISARM so the unconfirmed restore can complete.";
+ return false;
+ }
+ }
+
const auto last_attempt_us = g_last_disarm_attempt_us.load(std::memory_order_relaxed);
// Don't spam DISARM frames (they share the helper's job/message queues with APPLY/REVERT).
@@ -695,7 +725,6 @@ namespace {
// Fail-safe: if we recently initiated a helper restore, and DISARM couldn't be delivered quickly,
// terminate the helper so restore activity stops immediately (prevents virtual display crash loops).
- const auto last_revert_us = g_last_revert_us.load(std::memory_order_relaxed);
const bool revert_recent = (now_us - last_revert_us) < (30LL * 1000LL * 1000LL);
if (revert_recent) {
BOOST_LOG(warning) << "Display helper: DISARM could not be delivered within "
@@ -1113,9 +1142,17 @@ namespace display_helper_integration {
// Stream-start policy: if a helper is already running, hard-restart it immediately
// rather than attempting graceful STOP (avoids apply timeouts and wedged restore loops).
+ // Exception: if we recently asked the helper to restore and did not cancel it inside
+ // the short disarm grace window, keep that helper alive and let APPLY supersede the
+ // restore through IPC. Killing it here can strand the host in a partially restored
+ // physical-display mode when a monitor input is still switched away.
// In SYSTEM/no-user-session mode we still keep hard restart to recover stale pipe state,
// but we avoid in-process display API fallback if helper IPC remains unavailable.
- const bool hard_restart = (request.session != nullptr);
+ const bool restore_expected = restore_expected_with_live_helper();
+ const bool hard_restart = (request.session != nullptr) && !restore_expected;
+ if (request.session && restore_expected) {
+ BOOST_LOG(info) << "Display helper: reusing existing helper because an unconfirmed restore is pending; APPLY will supersede it.";
+ }
bool helper_ready = ensure_helper_started(hard_restart, true);
if (!helper_ready && hard_restart) {
@@ -1137,6 +1174,7 @@ namespace display_helper_integration {
const bool ok = platf::display_helper_client::send_apply_json(*payload);
BOOST_LOG(info) << "Display helper: APPLY dispatch result=" << (ok ? "true" : "false");
if (ok && request.session) {
+ g_restore_expected.store(false, std::memory_order_relaxed);
g_last_apply_completed_us.store(now_steady_us(), std::memory_order_relaxed);
set_active_session(
*request.session,
@@ -1254,6 +1292,11 @@ namespace display_helper_integration {
}
bool snapshot_current_display_state() {
+ if (restore_expected_with_live_helper()) {
+ BOOST_LOG(info) << "Display helper: skipping SNAPSHOT_CURRENT while an unconfirmed restore is pending.";
+ return false;
+ }
+
if (!ensure_helper_started()) {
BOOST_LOG(info) << "Display helper unavailable; cannot snapshot current display state.";
return false;
diff --git a/tools/display_settings_helper.cpp b/tools/display_settings_helper.cpp
index bbeafea835..609892796c 100644
--- a/tools/display_settings_helper.cpp
+++ b/tools/display_settings_helper.cpp
@@ -2231,6 +2231,10 @@ namespace {
// Track whether a revert/restore is currently pending
std::atomic restore_requested {false};
std::atomic restore_cancel_generation {0};
+ // True after the restore loop has made at least one restore attempt that has
+ // not yet been confirmed. DISARM/SNAPSHOT_CURRENT from a later stream-start
+ // probe must not cancel or overwrite that restore baseline.
+ std::atomic restore_attempted_unconfirmed {false};
// Guard: if a session restore succeeded recently, suppress Golden for a cooldown
std::atomic last_session_restore_success_ms {0};
// After a few consecutive confirmed session fallbacks, stop forcing golden
@@ -3162,6 +3166,8 @@ namespace {
return false;
}
+ restore_attempted_unconfirmed.store(true, std::memory_order_release);
+
const bool golden_first = always_restore_from_golden.load(std::memory_order_acquire);
if (!golden_first) {
reset_pending_golden_session_fallbacks();
@@ -3340,6 +3346,7 @@ namespace {
request_restore_cancel();
event_pump.stop();
event_pump_running.store(false, std::memory_order_release);
+ restore_attempted_unconfirmed.store(false, std::memory_order_release);
reset_restore_backoff();
restore_active_until_ms.store(0, std::memory_order_release);
last_restore_event_ms.store(0, std::memory_order_release);
@@ -3386,6 +3393,7 @@ namespace {
void clear_restore_origin() {
restore_origin_epoch.store(0, std::memory_order_release);
prefer_golden_if_current_missing.store(true, std::memory_order_release);
+ restore_attempted_unconfirmed.store(false, std::memory_order_release);
reset_pending_golden_session_fallbacks();
}
@@ -4854,8 +4862,17 @@ namespace {
state.retry_apply_on_topology.store(false, std::memory_order_release);
state.retry_revert_on_topology.store(false, std::memory_order_release);
} else if (type == MsgType::Disarm) {
+ if (state.restore_requested.load(std::memory_order_acquire) &&
+ state.restore_attempted_unconfirmed.load(std::memory_order_acquire)) {
+ BOOST_LOG(info) << "DISARM command ignored because an unconfirmed restore attempt is still pending.";
+ return;
+ }
state.disarm_restore_requests("DISARM command received");
} else if (type == MsgType::SnapshotCurrent) {
+ if (state.restore_requested.load(std::memory_order_acquire)) {
+ BOOST_LOG(info) << "Skipping current session snapshot refresh while restore is pending.";
+ return;
+ }
(void) state.refresh_current_snapshot_preserving_previous("snapshot-only");
} else if (type == MsgType::Ping) {
state.record_heartbeat_ping();
@@ -5164,7 +5181,11 @@ int main(int argc, char *argv[]) {
}
const auto connection_epoch = state.begin_connection_epoch();
- state.stop_restore_polling();
+ // Do not cancel restore polling merely because Sunshine connected. Stream start
+ // often opens the helper first for SNAPSHOT_CURRENT/DISARM probes; cancelling
+ // here can strand a prior, unconfirmed restore when a physical monitor is
+ // present but its input is switched away. APPLY/DISARM handlers decide
+ // explicitly whether a restore should be superseded.
state.begin_heartbeat_monitoring();
// Reset and start per-connection command worker so IPC stays responsive even during heavy display work.
From 51d7eaf5d0af1bb823dc89e9f413dcabb276a815 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Sat, 23 May 2026 01:26:37 +1000
Subject: [PATCH 36/60] docs: record upstream sync tracker context
---
docs/community-research.md | 3 ++-
docs/roadmap-issues/setup-doctor-client-profiles.md | 7 ++++++-
docs/upstream-issue-radar.md | 3 ++-
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 3 +++
4 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/docs/community-research.md b/docs/community-research.md
index de6ea2cfe3..09394c91d5 100644
--- a/docs/community-research.md
+++ b/docs/community-research.md
@@ -178,7 +178,8 @@ candidate scoring are reviewed.
## Next Actions
-1. Open a public roadmap issue for Setup Doctor and Client Profiles.
+1. Keep the public maintainer tracker for Setup Doctor and Client Profiles
+ honest: it is a maintainer planning issue, not a user-reported issue.
2. Keep the first implementation read-only wherever possible.
3. Add a Troubleshooting page cursor card as the first visible Setup Doctor seed.
4. Create a fixture matrix after the next VM build and Shield TV stream test.
diff --git a/docs/roadmap-issues/setup-doctor-client-profiles.md b/docs/roadmap-issues/setup-doctor-client-profiles.md
index 3eea726b85..243ed74a5d 100644
--- a/docs/roadmap-issues/setup-doctor-client-profiles.md
+++ b/docs/roadmap-issues/setup-doctor-client-profiles.md
@@ -1,4 +1,9 @@
-# Roadmap: Nimbus Setup Doctor And Client Profiles
+# Tracking: Nimbus Setup Doctor And Client Profiles
+
+Public tracker: https://github.com/kunolabs/Nimbus/issues/4
+
+Maintainer note: this is a Nimbus bootstrap planning tracker, not a
+user-reported issue or a claim of existing community demand.
## Problem
diff --git a/docs/upstream-issue-radar.md b/docs/upstream-issue-radar.md
index cf3f6a4213..7c5b647c97 100644
--- a/docs/upstream-issue-radar.md
+++ b/docs/upstream-issue-radar.md
@@ -51,7 +51,8 @@ scoped.
| Issue | Bucket | Why |
| --- | --- | --- |
-| [#236 HEVC Main10/HDR not advertised despite `hevc_mode = 3`](https://github.com/Nonary/Vibepollo/issues/236) | Upstream fixed | Labeled `fixed` upstream. Wait for release/sync or inspect the fixing commit before creating Nimbus work. |
+| [#236 HEVC Main10/HDR not advertised despite `hevc_mode = 3`](https://github.com/Nonary/Vibepollo/issues/236) | Synced | Upstream 1.16.0-alpha.4 HDR/10-bit and NVENC API 12.1 fixes were cherry-picked into Nimbus after the 2026-05-23 upstream refresh. |
+| [#238 Secondary monitor never recovers properly](https://github.com/Nonary/Vibepollo/issues/238) | Partially synced | Upstream 1.16.0-alpha.4 display-helper restore and golden snapshot fixes were cherry-picked. Keep VM validation before marking closed for Nimbus. |
## Docs And Support
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index 7095a21018..e07918556c 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -52,6 +52,9 @@ has wider testers.
Profiles, Cursor Doctor, and the future Game Discovery Inbox direction.
- Added the first Cursor Doctor card to the Troubleshooting page and cleaned
remaining Playnite cleanup copy that still said Vibeshine.
+- Cherry-picked upstream Vibepollo display, HDR/10-bit, NVENC bit-depth, and
+ display-helper restore fixes from the refreshed `upstream-vibepollo/master`
+ while preserving Nimbus installer cache naming.
## Compatibility Notes
From 17b2ad2ebc854cf1c79cc2adfcf84beb15dcf002 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Sat, 23 May 2026 01:31:11 +1000
Subject: [PATCH 37/60] docs: add streaming recipe fixtures
---
.github/ISSUE_TEMPLATE/bug-report.yml | 55 +++++++-
README.md | 3 +
docs/fixture-matrix.md | 45 ++++++
docs/guides.md | 13 +-
docs/streaming-recipes.md | 132 ++++++++++++++++++
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 3 +
6 files changed, 245 insertions(+), 6 deletions(-)
create mode 100644 docs/fixture-matrix.md
create mode 100644 docs/streaming-recipes.md
diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml
index 2862f55729..05b88c36cf 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.yml
+++ b/.github/ISSUE_TEMPLATE/bug-report.yml
@@ -17,6 +17,25 @@ body:
validations:
required: true
+ - type: dropdown
+ id: issue-area
+ attributes:
+ label: Issue Area
+ description: Select the closest area. Pick the most visible symptom if more than one applies.
+ options:
+ - Pairing / client connection
+ - Display / virtual display / HDR
+ - Frame pacing / stutter / bitrate
+ - Audio / channel layout / delay
+ - Controller / gamepad / input
+ - Cursor / mouse visibility
+ - Playnite / app launch / app exit
+ - Installer / upgrade / uninstall
+ - Web UI / API
+ - Other
+ validations:
+ required: true
+
- type: dropdown
id: host-os
attributes:
@@ -37,7 +56,7 @@ body:
id: host-gpu
attributes:
label: Host GPU and Driver
- description: Example: RTX 4080, NVIDIA 576.xx.
+ description: "Example: RTX 4080, NVIDIA 576.xx."
validations:
required: true
@@ -45,10 +64,42 @@ body:
id: client
attributes:
label: Client Device and App
- description: Example: NVIDIA Shield TV Pro, Artemis v20.2.6, 4K 120 Hz HEVC HDR.
+ description: "Example: NVIDIA Shield TV Pro, Artemis v20.2.6, 4K 120 Hz HEVC HDR."
validations:
required: true
+ - type: input
+ id: stream-settings
+ attributes:
+ label: Stream Settings
+ description: "Example: 3840x2160, 60 FPS, HEVC, HDR off, 80 Mbps."
+ validations:
+ required: false
+
+ - type: input
+ id: display-setup
+ attributes:
+ label: Host Display Setup
+ description: "Example: physical LG OLED, SudoVDA virtual display, dummy plug, headless VM."
+ validations:
+ required: false
+
+ - type: input
+ id: network-path
+ attributes:
+ label: Network Path
+ description: "Example: wired LAN, Wi-Fi 6, Tailscale direct, Tailscale relay, WireGuard, WAN."
+ validations:
+ required: false
+
+ - type: textarea
+ id: input-audio
+ attributes:
+ label: Input And Audio Notes
+ description: Mention gamepads, mouse/cursor behavior, audio sink, stereo/5.1/7.1, Bluetooth, eARC, or soundbar details if relevant.
+ validations:
+ required: false
+
- type: textarea
id: reproduction
attributes:
diff --git a/README.md b/README.md
index 53d63dd6a8..5a0da2e44b 100644
--- a/README.md
+++ b/README.md
@@ -75,6 +75,9 @@ Early Nimbus work is focused on:
See [ROADMAP.md](ROADMAP.md) for the current maintainer roadmap.
See [docs/community-research.md](docs/community-research.md) for the community
setup research behind Setup Doctor, Client Profiles, and future fixture work.
+See [docs/streaming-recipes.md](docs/streaming-recipes.md) and
+[docs/fixture-matrix.md](docs/fixture-matrix.md) for the first repeatable
+testing surfaces.
See [docs/ui-identity-plan.md](docs/ui-identity-plan.md) for the staged Nimbus
Web UI identity direction.
diff --git a/docs/fixture-matrix.md b/docs/fixture-matrix.md
new file mode 100644
index 0000000000..a67de05b0d
--- /dev/null
+++ b/docs/fixture-matrix.md
@@ -0,0 +1,45 @@
+# Nimbus Fixture Matrix
+
+Snapshot date: 2026-05-23
+
+This matrix records real tested host/client setups. Keep it factual: only add a
+row after a local or community tester has actually run the setup.
+
+## Status Legend
+
+| Status | Meaning |
+| --- | --- |
+| Pass | Tested successfully with no observed issue in the recorded scenario. |
+| Partial | Stream works, but there is a caveat or unverified surface. |
+| Fail | Reproduced failure with enough evidence to investigate. |
+| Planned | Intended fixture, not yet tested. |
+
+## Current Fixtures
+
+| Date | Status | Host | Client | Display | Network | Scenario | Evidence |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 2026-05-21 | Partial | Windows 11 VM on VMware, AMD Ryzen 7 5700X3D host, VMware SVGA 3D | Artemis on Shield TV | 1920x1080@60, WebRTC observed in UI | LAN, VM IP 192.168.51.128 | Pair, stream, disconnect | Manual VM smoke passed; service name remains inherited `ApolloService`; next build must retest naming and upstream display fixes. |
+
+## Planned Fixtures
+
+| Priority | Fixture | Why |
+| --- | --- | --- |
+| High | Windows 11 physical host to Shield TV Pro 4K60 SDR | Main living-room baseline. |
+| High | Windows 11 physical host to Shield TV Pro 4K60 HDR | Validates HDR/10-bit sync and client behavior. |
+| High | SudoVDA virtual display restore after disconnect | Core inherited reliability issue and upstream sync validation. |
+| Medium | Steam Deck/handheld native resolution profile | Client Profiles direction. |
+| Medium | Tailscale remote stream | Network diagnostics direction. |
+| Medium | Playnite Fullscreen launch and clean exit | Library integration and app lifecycle confidence. |
+
+## Evidence Checklist
+
+- Nimbus commit hash.
+- Installer artifact hash if testing a packaged build.
+- Host OS build, GPU, driver, and display type.
+- Client device, client app/version, resolution, FPS, codec, HDR.
+- Network path: LAN, Wi-Fi, Ethernet, Tailscale, WireGuard, WAN.
+- Pairing result.
+- Launch result.
+- Disconnect/restore result.
+- Exported log bundle path or attached issue link.
+
diff --git a/docs/guides.md b/docs/guides.md
index 8f3d056dc2..2f36f9ee60 100644
--- a/docs/guides.md
+++ b/docs/guides.md
@@ -1,9 +1,14 @@
# Guides
-@admonition{Community | A collection of guides written by the community is available on our
-[blog](https://app.lizardbyte.dev/blog).
-Feel free to contribute your own tips and trips by making a PR to
-[LizardByte.github.io](https://github.com/LizardByte/LizardByte.github.io).}
+Nimbus is building a practical guide set around repeatable home-streaming
+setups, not one-size-fits-all tuning claims.
+
+- [Streaming Recipes](streaming-recipes.md): starting points for Shield TV,
+ Android TV, Steam Deck, OLED HDR, headless hosts, and remote overlay networks.
+- [Fixture Matrix](fixture-matrix.md): real tested host/client combinations and
+ evidence expectations.
+- [Community Research](community-research.md): source research behind Setup
+ Doctor, Client Profiles, Cursor Doctor, and Game Discovery Inbox.
diff --git a/docs/streaming-recipes.md b/docs/streaming-recipes.md
new file mode 100644
index 0000000000..9f0cb9d488
--- /dev/null
+++ b/docs/streaming-recipes.md
@@ -0,0 +1,132 @@
+# Nimbus Streaming Recipes
+
+Snapshot date: 2026-05-23
+
+These recipes are starting points for repeatable community testing. They are not
+guaranteed optimal settings. Record what actually works in
+`docs/fixture-matrix.md` after testing.
+
+## Shield TV / Android TV 4K60
+
+Best for living-room controller-first play.
+
+| Setting | Starting Point |
+| --- | --- |
+| Client | Artemis or Moonlight Android TV |
+| Resolution | 3840x2160 |
+| Frame rate | 60 FPS |
+| Codec | HEVC when supported |
+| HDR | Enable only after SDR is stable |
+| Network | Wired Ethernet preferred |
+| Host display | SudoVDA virtual display or physical 4K display |
+| App launch | Playnite Fullscreen or direct game app |
+
+Checks:
+
+- Pair client and confirm stream starts from the TV device.
+- Confirm the Windows cursor is not visible in controller-first games.
+- Confirm disconnect restores the expected host display state.
+- Export logs after one successful stream and one disconnect.
+
+## Shield TV / Android TV 4K120
+
+Best for high-refresh displays where the full chain supports 120 Hz.
+
+| Setting | Starting Point |
+| --- | --- |
+| Client | Artemis or Moonlight Android TV |
+| Resolution | 3840x2160 |
+| Frame rate | 120 FPS |
+| Codec | HEVC or AV1 if both sides support it |
+| HDR | Enable after 4K120 SDR is stable |
+| Network | Wired Ethernet or proven low-latency Wi-Fi 6/6E |
+| Frame pacing | Validate display refresh, RTSS cap, and client-reported FPS |
+
+Checks:
+
+- Confirm the host display is actually running near 120 Hz.
+- Watch for 119.88/120 mismatch and frame pacing jitter.
+- Record whether WGC, DXGI, or frame-generation capture is used.
+
+## Steam Deck / Handheld
+
+Best for handheld streaming with client-native aspect ratio.
+
+| Setting | Starting Point |
+| --- | --- |
+| Resolution | 1280x800 or client-native |
+| Frame rate | 60, 90, or native FPS depending on client |
+| Bitrate | Start conservative, then increase |
+| Input | Gamepad-first; test Steam Input behavior |
+| Launcher | Playnite, Steam Big Picture, or direct app |
+
+Checks:
+
+- Confirm the game renders without aspect-ratio stretching.
+- Confirm controller order and rumble behavior.
+- Confirm bitrate does not outrun Wi-Fi conditions.
+
+## OLED 4K HDR
+
+Best for enthusiasts validating HDR and 10-bit behavior.
+
+| Setting | Starting Point |
+| --- | --- |
+| Resolution | 3840x2160 |
+| Frame rate | 60 or 120 FPS |
+| Codec | HEVC Main10 or AV1 10-bit where supported |
+| HDR | Validate SDR first, then HDR |
+| Display | Physical HDR display or virtual display with known-good HDR metadata |
+
+Checks:
+
+- Confirm Windows HDR state before and during stream.
+- Confirm client HDR mode actually engages.
+- Record encoder, bit depth, and client codec.
+- Export logs if HDR falls back to SDR or the image looks washed out.
+
+## Headless Windows Host
+
+Best for PCs without an attached gaming display.
+
+| Setting | Starting Point |
+| --- | --- |
+| Display | SudoVDA first; dummy plug as fallback |
+| Restore | Create a golden display snapshot before testing |
+| App launch | Direct app first, then Playnite |
+| Access | Keep local/remote recovery path available |
+
+Checks:
+
+- Confirm the virtual display appears before pairing.
+- Confirm stream-end restore does not strand the host in the wrong layout.
+- Export display-helper logs after restore.
+
+## Remote Tailscale / WireGuard
+
+Best for controlled remote-home testing.
+
+| Setting | Starting Point |
+| --- | --- |
+| Pairing | Pair locally first if possible |
+| Address | Use the overlay IP only after LAN success |
+| Bitrate | Start lower than LAN |
+| Network | Verify direct path vs relay where your overlay exposes it |
+
+Checks:
+
+- Confirm LAN stream works before remote testing.
+- Record whether manual IP add was needed.
+- Export logs for RTSP, connection timeout, or disconnect failures.
+
+## Cursor Troubleshooting Mini-Recipe
+
+Use this when the Windows cursor remains visible, disappears, duplicates, or
+appears offset.
+
+1. Identify which cursor is visible: host cursor, client cursor, or game cursor.
+2. Check whether the client has a local cursor toggle or touch/mouse mode.
+3. Test one controller-first game and one mouse-first desktop/app session.
+4. Note whether the host is using a physical display, SudoVDA, dummy plug, or
+ HDR/virtual-display setup.
+5. Search Nimbus logs for `cursor`, `mouse`, `input`, and capture method.
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index e07918556c..a2b3d24e81 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -55,6 +55,9 @@ has wider testers.
- Cherry-picked upstream Vibepollo display, HDR/10-bit, NVENC bit-depth, and
display-helper restore fixes from the refreshed `upstream-vibepollo/master`
while preserving Nimbus installer cache naming.
+- Added streaming recipes, a fixture matrix, and a richer bug report template
+ for display, HDR, audio, controller, cursor, network, Playnite, and installer
+ evidence.
## Compatibility Notes
From 52a6578540788fdce185190532f3c41f5445d928 Mon Sep 17 00:00:00 2001
From: David Lane <42013603+ReenigneArcher@users.noreply.github.com>
Date: Thu, 7 May 2026 21:47:14 -0400
Subject: [PATCH 38/60] fix(security): reject untrusted client certificates
Port upstream Vibepollo/Sunshine certificate-auth hardening by no longer accepting X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY during client certificate verification.
Upstream commit: be0e85bcf1947bc22f02e7882cf67a32944f28b5
---
src/crypto.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/crypto.cpp b/src/crypto.cpp
index 43f71b80a8..d6313182fe 100644
--- a/src/crypto.cpp
+++ b/src/crypto.cpp
@@ -35,8 +35,6 @@ namespace crypto {
// Expired or not-yet-valid certificates are fine. Sometimes Moonlight is running on embedded devices
// that don't have accurate clocks (or haven't yet synchronized by the time Moonlight first runs).
// This behavior also matches what GeForce Experience does.
- // TODO: Checking for X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY is a temporary workaround to get moonlight-embedded to work on the raspberry pi
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
case X509_V_ERR_CERT_NOT_YET_VALID:
case X509_V_ERR_CERT_HAS_EXPIRED:
return 1;
From 10ed2c3207b87fee107d954080ac003ab2df5a90 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Sun, 24 May 2026 00:17:06 +1000
Subject: [PATCH 39/60] docs: add Apollo switch readiness path
---
README.md | 2 +
docs/apollo-to-nimbus-switch.md | 142 +++++++
docs/guides.md | 2 +
docs/packaging-identity-plan.md | 7 +
docs/windows-installer-fixture.md | 5 +-
.../bootstrapper/VibeshineInstaller.cs | 3 +-
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 9 +
scripts/collect_apollo_switch_bundle.ps1 | 359 ++++++++++++++++++
8 files changed, 527 insertions(+), 2 deletions(-)
create mode 100644 docs/apollo-to-nimbus-switch.md
create mode 100644 scripts/collect_apollo_switch_bundle.ps1
diff --git a/README.md b/README.md
index 5a0da2e44b..a7b5d5fc0e 100644
--- a/README.md
+++ b/README.md
@@ -78,6 +78,8 @@ setup research behind Setup Doctor, Client Profiles, and future fixture work.
See [docs/streaming-recipes.md](docs/streaming-recipes.md) and
[docs/fixture-matrix.md](docs/fixture-matrix.md) for the first repeatable
testing surfaces.
+See [docs/apollo-to-nimbus-switch.md](docs/apollo-to-nimbus-switch.md) before
+testing Nimbus on a host that already runs Apollo.
See [docs/ui-identity-plan.md](docs/ui-identity-plan.md) for the staged Nimbus
Web UI identity direction.
diff --git a/docs/apollo-to-nimbus-switch.md b/docs/apollo-to-nimbus-switch.md
new file mode 100644
index 0000000000..f427d6bc12
--- /dev/null
+++ b/docs/apollo-to-nimbus-switch.md
@@ -0,0 +1,142 @@
+# Apollo To Nimbus Switch Guide
+
+Snapshot date: 2026-05-24
+
+This guide is for maintainers and early testers who already use Apollo and want
+to try Nimbus without losing apps, Web UI credentials, paired clients, covers,
+or configuration history.
+
+Nimbus is still in alpha-prep. Do not run the first switch attempt on a
+daily-use host unless you have a rollback path.
+
+## What Can Be Carried Over
+
+Apollo, Vibepollo, and Nimbus share the same inherited configuration shape for
+the first Nimbus alpha:
+
+| Item | Usually stored in | Why it matters |
+| --- | --- | --- |
+| Apps | `apps.json` | Custom apps, Playnite-synced entries, images, launch commands. |
+| Host settings | `sunshine.conf` | Display, encoder, audio, network, Playnite, RTSS, and app behavior. |
+| Web UI users and state | `sunshine_state.json` | Web UI credentials, paired-client state, and host state. |
+| Compatibility state | `vibeshine_state.json` | Vibepollo-era state if present. |
+| Client certificates and keys | `credentials/` | Pairing identity and HTTPS/GameStream certificates. |
+| Covers | `covers/` | App artwork referenced by `apps.json`. |
+
+The switch bundle may contain password hashes, private keys, client
+certificates, and device identity data. Treat it as sensitive.
+
+## Current Installer Reality
+
+The Nimbus installer can detect Apollo and uninstall it before installing
+Nimbus. That is required because the projects share inherited service and
+upgrade identity.
+
+However, MSI-style Apollo to Nimbus config carry-over is not yet a proven
+automatic migration. A safe alpha switch should create a separate Apollo config
+bundle first, then import it into Nimbus only after the new install is present
+and the Nimbus service is stopped.
+
+## Recommended Switch Flow
+
+```mermaid
+flowchart TD
+ A["Apollo daily host"] --> B["Export Apollo switch bundle"]
+ B --> C["Record Apollo version and config path"]
+ C --> D["Install Nimbus candidate"]
+ D --> E["Stop Nimbus service"]
+ E --> F["Import Apollo bundle into Nimbus config"]
+ F --> G["Start Nimbus service"]
+ G --> H["Open Web UI and confirm apps"]
+ H --> I["Pair/stream Shield TV smoke"]
+ I --> J{"Good for one week?"}
+ J -- "yes" --> K["Promote Nimbus to daily host"]
+ J -- "no" --> L["Rollback to Apollo backup"]
+```
+
+## Export Apollo Config
+
+Run this from an elevated PowerShell window before uninstalling Apollo:
+
+```powershell
+powershell -ExecutionPolicy Bypass -File .\scripts\collect_apollo_switch_bundle.ps1
+```
+
+The script looks for Apollo in the registry and common install/config paths. It
+writes a timestamped bundle under `nimbus-switch-bundles/` with:
+
+- `config/`: copied Apollo config files and folders.
+- `switch-bundle-summary.md`: human-readable summary.
+- `switch-bundle-manifest.json`: file inventory and SHA256 hashes.
+
+If Apollo uses a non-standard config path, pass it explicitly:
+
+```powershell
+powershell -ExecutionPolicy Bypass -File .\scripts\collect_apollo_switch_bundle.ps1 `
+ -SourceConfigDir "C:\Program Files\Apollo\config"
+```
+
+## Import Into Nimbus
+
+After installing Nimbus, stop the service before importing:
+
+```powershell
+Stop-Service ApolloService -ErrorAction SilentlyContinue
+```
+
+Then import from the Apollo source or exported bundle config into Nimbus:
+
+```powershell
+powershell -ExecutionPolicy Bypass -File .\scripts\collect_apollo_switch_bundle.ps1 `
+ -SourceConfigDir ".\nimbus-switch-bundles\-apollo-to-nimbus\config" `
+ -NimbusConfigDir "C:\Program Files\Nimbus\config" `
+ -ImportToNimbus `
+ -Force
+```
+
+Restart Nimbus:
+
+```powershell
+Start-Service ApolloService
+```
+
+`-Force` allows known config files and folders in the Nimbus config directory to
+be replaced. The script backs up existing Nimbus copies into the same switch
+bundle before replacement.
+
+## What To Check After Import
+
+- Web UI opens at `https://localhost:47990`.
+- Apps page contains your expected Apollo apps.
+- Covers load or fail gracefully.
+- Clients page shows expected paired devices, or pairing still works if you
+ intentionally skipped credentials.
+- Shield TV / Artemis can pair, start a short stream, and disconnect cleanly.
+- General display, virtual display, HDR, audio, and Playnite settings still look
+ sane.
+
+## Rollback
+
+If Nimbus is not ready:
+
+1. Export the current Nimbus config with the same switch script.
+2. Uninstall Nimbus without factory reset unless you intentionally want to wipe
+ its config.
+3. Reinstall Apollo.
+4. Restore the saved Apollo bundle into Apollo's config directory.
+5. Start Apollo and verify apps, clients, and streaming.
+
+Do not delete the original Apollo switch bundle until Nimbus has been your
+daily host for at least a week.
+
+## Release Gate
+
+The first Nimbus alpha should not claim seamless Apollo migration until this
+flow has been tested on a physical host:
+
+- Apollo installed and working.
+- Apollo switch bundle exported.
+- Nimbus installed over or after Apollo.
+- Apollo bundle imported into Nimbus.
+- Apps, settings, credentials, pairing, stream start, and disconnect verified.
+- Rollback path recorded.
diff --git a/docs/guides.md b/docs/guides.md
index 2f36f9ee60..85cc97a36d 100644
--- a/docs/guides.md
+++ b/docs/guides.md
@@ -7,6 +7,8 @@ setups, not one-size-fits-all tuning claims.
Android TV, Steam Deck, OLED HDR, headless hosts, and remote overlay networks.
- [Fixture Matrix](fixture-matrix.md): real tested host/client combinations and
evidence expectations.
+- [Apollo To Nimbus Switch Guide](apollo-to-nimbus-switch.md): backup, import,
+ and rollback guidance for Apollo users testing Nimbus.
- [Community Research](community-research.md): source research behind Setup
Doctor, Client Profiles, Cursor Doctor, and Game Discovery Inbox.
diff --git a/docs/packaging-identity-plan.md b/docs/packaging-identity-plan.md
index 44fc2cbd0c..6be575a399 100644
--- a/docs/packaging-identity-plan.md
+++ b/docs/packaging-identity-plan.md
@@ -201,6 +201,8 @@ Acceptance criteria:
- The installer does not publish or sign using upstream destinations. Status:
passed for local unsigned validation artifacts.
- Upgrade behavior from an existing Vibepollo/Apollo install is recorded.
+- Apollo-to-Nimbus config carry-over is validated with an explicit backup/import
+ bundle before any release note claims seamless migration.
- Fresh install and uninstall behavior is recorded.
- Release notes disclose inherited runtime ids that remain in place.
@@ -244,3 +246,8 @@ Run the installer in a Windows VM or snapshot fixture. Record fresh install,
upgrade from Apollo/Vibepollo where practical, uninstall, reinstall, generated
shortcuts, Add/Remove Programs text, services, and config behavior before
creating any `nimbus-v*` tag.
+
+For Apollo upgrade testing, use `docs/apollo-to-nimbus-switch.md` first. The
+current alpha-prep installer detects and removes Apollo, but Apollo config
+carry-over into the Nimbus install directory must be backed up and verified
+explicitly.
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index e4a01e10a9..a4e2826136 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -70,7 +70,7 @@ so user-facing version surfaces no longer look like an unversioned build.
| Uninstall | Yes | Pending | Add/Remove Programs entry removed and service stopped |
| Reinstall after uninstall | Yes | Pending | Reinstall completes without manual cleanup |
| Upgrade from Vibepollo | Strongly recommended | Pending | Config, credentials, and paired-client state checked |
-| Upgrade from Apollo | Strongly recommended | Pending | Config, credentials, and paired-client state checked |
+| Upgrade from Apollo | Strongly recommended | Pending | Export/import bundle, config, credentials, and paired-client state checked |
| Coexistence with Sunshine | Optional for alpha | Pending | Record whether install replaces or coexists |
| Windows SmartScreen/AV behavior | Yes | Pending | Unsigned prompt or false-positive notes recorded |
@@ -115,6 +115,9 @@ Still blocking the alpha gate:
Programs entry.
- Confirm reinstall after uninstall completes without manual cleanup.
- Record upgrade behavior from Apollo and/or Vibepollo where practical.
+- For Apollo upgrade testing, use
+ [Apollo To Nimbus Switch Guide](apollo-to-nimbus-switch.md) and attach the
+ sanitized `switch-bundle-summary.md` plus post-import fixture evidence.
## Evidence Commands
diff --git a/packaging/windows/bootstrapper/VibeshineInstaller.cs b/packaging/windows/bootstrapper/VibeshineInstaller.cs
index f63fac4b6e..0d314e9e83 100644
--- a/packaging/windows/bootstrapper/VibeshineInstaller.cs
+++ b/packaging/windows/bootstrapper/VibeshineInstaller.cs
@@ -1261,6 +1261,7 @@ private static string BuildApolloInstallWarning(InstallerRunner.InstalledProduct
return "Apollo" + versionSuffix + " was detected on this PC.\n\n"
+ "Nimbus replaces Apollo and cannot be installed while Apollo is installed.\n"
+ "Continuing will uninstall Apollo before installation.\n\n"
+ + "This alpha does not yet prove automatic Apollo settings import. Back up Apollo first if you want to carry apps, credentials, paired clients, or host settings into Nimbus.\n\n"
+ "Click Uninstall Apollo to proceed.";
}
@@ -1286,7 +1287,7 @@ private string BuildLegacyApolloMigrationWarning() {
return "Legacy Apollo" + versionSuffix + " was detected on this PC.\n\n"
+ "Nimbus replaces legacy Apollo and will automatically uninstall it first, then install Nimbus.\n"
- + "No settings will be carried over.\n\n"
+ + "This alpha does not automatically import legacy Apollo settings. Back up Apollo first if you want to carry apps, credentials, paired clients, or host settings into Nimbus.\n\n"
+ "Click Uninstall Apollo to proceed.";
}
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index a2b3d24e81..ad982f676b 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -55,9 +55,15 @@ has wider testers.
- Cherry-picked upstream Vibepollo display, HDR/10-bit, NVENC bit-depth, and
display-helper restore fixes from the refreshed `upstream-vibepollo/master`
while preserving Nimbus installer cache naming.
+- Ported the upstream client-certificate authentication hardening so Nimbus no
+ longer accepts untrusted client certificates that fail local issuer
+ verification.
- Added streaming recipes, a fixture matrix, and a richer bug report template
for display, HDR, audio, controller, cursor, network, Playnite, and installer
evidence.
+- Added an Apollo-to-Nimbus switch bundle script and switch guide so existing
+ Apollo apps, host settings, credentials, paired clients, and covers can be
+ backed up and imported deliberately during alpha testing.
## Compatibility Notes
@@ -71,6 +77,8 @@ feedback:
a dedicated migration plan is built and tested.
- Existing Apollo or Vibepollo users should treat this alpha as a test build and
back up configuration before installing over a daily-use host.
+- Automatic Apollo settings import is not yet a proven installer guarantee; use
+ the Apollo-to-Nimbus switch guide for controlled export/import testing.
## Verification
@@ -125,6 +133,7 @@ Pending before release:
- Retest the General and Files settings pages for inherited visible names in
the next candidate build.
- Upgrade behavior from Apollo and/or Vibepollo where practical.
+- Apollo-to-Nimbus switch bundle export/import on a physical host.
## Known Issues And Caveats
diff --git a/scripts/collect_apollo_switch_bundle.ps1 b/scripts/collect_apollo_switch_bundle.ps1
new file mode 100644
index 0000000000..3876865846
--- /dev/null
+++ b/scripts/collect_apollo_switch_bundle.ps1
@@ -0,0 +1,359 @@
+#Requires -Version 5.1
+[CmdletBinding(SupportsShouldProcess = $true)]
+param(
+ [string]$SourceConfigDir = "",
+ [string]$NimbusConfigDir = "",
+ [string]$OutputDir = "",
+ [switch]$ImportToNimbus,
+ [switch]$SkipCredentials,
+ [switch]$Force
+)
+
+$ErrorActionPreference = "Stop"
+
+$ExportFiles = @(
+ "apps.json",
+ "sunshine.conf",
+ "sunshine_state.json",
+ "vibeshine_state.json",
+ "virtual_display_cache.json",
+ "nvprefs_undo.json"
+)
+
+$ImportFiles = @(
+ "apps.json",
+ "sunshine.conf",
+ "sunshine_state.json",
+ "vibeshine_state.json"
+)
+
+$ExportDirectories = @("covers")
+$ImportDirectories = @("covers")
+if (-not $SkipCredentials) {
+ $ExportDirectories += "credentials"
+ $ImportDirectories += "credentials"
+}
+
+function Get-InstallLocationsFromRegistry {
+ param([string]$NamePattern)
+
+ $roots = @(
+ "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*",
+ "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
+ "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*"
+ )
+
+ foreach ($root in $roots) {
+ Get-ItemProperty -Path $root -ErrorAction SilentlyContinue |
+ Where-Object { $_.DisplayName -match $NamePattern } |
+ ForEach-Object {
+ [PSCustomObject]@{
+ DisplayName = $_.DisplayName
+ InstallLocation = $_.InstallLocation
+ }
+ }
+ }
+}
+
+function Test-ConfigCandidate {
+ param([string]$Path)
+
+ if ([string]::IsNullOrWhiteSpace($Path) -or -not (Test-Path -LiteralPath $Path -PathType Container)) {
+ return $false
+ }
+
+ foreach ($name in @("apps.json", "sunshine.conf", "sunshine_state.json", "credentials", "covers")) {
+ if (Test-Path -LiteralPath (Join-Path $Path $name)) {
+ return $true
+ }
+ }
+
+ return $false
+}
+
+function Resolve-ConfigDirectory {
+ param(
+ [string]$ExplicitPath,
+ [string]$ProductPattern,
+ [string[]]$FallbackRoots
+ )
+
+ $candidates = New-Object System.Collections.Generic.List[string]
+
+ if (-not [string]::IsNullOrWhiteSpace($ExplicitPath)) {
+ $candidates.Add($ExplicitPath)
+ }
+
+ Get-InstallLocationsFromRegistry -NamePattern $ProductPattern |
+ Where-Object { -not [string]::IsNullOrWhiteSpace($_.InstallLocation) } |
+ ForEach-Object { $candidates.Add($_.InstallLocation) }
+
+ foreach ($root in $FallbackRoots) {
+ if (-not [string]::IsNullOrWhiteSpace($root)) {
+ $candidates.Add($root)
+ }
+ }
+
+ foreach ($candidate in $candidates | Select-Object -Unique) {
+ $expanded = [Environment]::ExpandEnvironmentVariables($candidate.Trim().Trim('"'))
+ $configChild = Join-Path $expanded "config"
+ if (Test-ConfigCandidate -Path $configChild) {
+ return (Resolve-Path -LiteralPath $configChild).ProviderPath
+ }
+ if (Test-ConfigCandidate -Path $expanded) {
+ return (Resolve-Path -LiteralPath $expanded).ProviderPath
+ }
+ }
+
+ return ""
+}
+
+function Copy-KnownItem {
+ param(
+ [string]$Source,
+ [string]$Destination,
+ [bool]$Overwrite
+ )
+
+ if (-not (Test-Path -LiteralPath $Source)) {
+ return "missing"
+ }
+
+ if ((Test-Path -LiteralPath $Destination) -and -not $Overwrite) {
+ return "skipped-existing"
+ }
+
+ if (Test-Path -LiteralPath $Destination) {
+ if ($PSCmdlet.ShouldProcess($Destination, "replace existing item")) {
+ Remove-Item -LiteralPath $Destination -Recurse -Force
+ }
+ }
+
+ $destinationParent = Split-Path -Parent $Destination
+ if (-not (Test-Path -LiteralPath $destinationParent)) {
+ New-Item -ItemType Directory -Path $destinationParent -Force | Out-Null
+ }
+
+ if ($PSCmdlet.ShouldProcess($Destination, "copy from $Source")) {
+ Copy-Item -LiteralPath $Source -Destination $Destination -Recurse -Force
+ }
+
+ return "copied"
+}
+
+function Get-FileInventory {
+ param([string]$Root)
+
+ if (-not (Test-Path -LiteralPath $Root)) {
+ return @()
+ }
+
+ Get-ChildItem -LiteralPath $Root -Recurse -File -ErrorAction SilentlyContinue |
+ ForEach-Object {
+ $relative = $_.FullName.Substring($Root.Length).TrimStart("\", "/")
+ $hash = Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256
+ [PSCustomObject]@{
+ Path = $relative
+ Length = $_.Length
+ Sha256 = $hash.Hash
+ }
+ }
+}
+
+function Repair-CredentialsAcl {
+ param([string]$ConfigDir)
+
+ $credentialsDir = Join-Path $ConfigDir "credentials"
+ if (-not (Test-Path -LiteralPath $credentialsDir -PathType Container)) {
+ return
+ }
+
+ $icacls = Join-Path $env:SystemRoot "System32\icacls.exe"
+ & $icacls $credentialsDir "/inheritance:r" | Out-Null
+ & $icacls $credentialsDir "/grant:r" "*S-1-5-18:(OI)(CI)(F)" | Out-Null
+ & $icacls $credentialsDir "/grant:r" "*S-1-5-32-544:(OI)(CI)(F)" | Out-Null
+ & $icacls $credentialsDir "/grant:r" "*S-1-5-32-545:(R)" | Out-Null
+}
+
+$apolloFallbackRoots = @(
+ "$env:ProgramFiles\Apollo",
+ "${env:ProgramFiles(x86)}\Apollo",
+ "$env:ProgramData\Apollo",
+ "$env:LOCALAPPDATA\Apollo",
+ "$env:APPDATA\Apollo"
+)
+
+$sourceConfig = Resolve-ConfigDirectory `
+ -ExplicitPath $SourceConfigDir `
+ -ProductPattern "Apollo" `
+ -FallbackRoots $apolloFallbackRoots
+
+if ([string]::IsNullOrWhiteSpace($sourceConfig)) {
+ throw "Apollo config directory was not found. Pass -SourceConfigDir with the Apollo config path or an exported bundle config path."
+}
+
+$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
+if ([string]::IsNullOrWhiteSpace($OutputDir)) {
+ $OutputDir = Join-Path (Get-Location) "nimbus-switch-bundles\$timestamp-apollo-to-nimbus"
+}
+
+New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
+$resolvedOutput = (Resolve-Path -LiteralPath $OutputDir).ProviderPath
+$bundleConfig = Join-Path $resolvedOutput "config"
+New-Item -ItemType Directory -Path $bundleConfig -Force | Out-Null
+
+$actions = New-Object System.Collections.Generic.List[object]
+
+foreach ($name in $ExportFiles) {
+ $source = Join-Path $sourceConfig $name
+ $destination = Join-Path $bundleConfig $name
+ $status = Copy-KnownItem -Source $source -Destination $destination -Overwrite $true
+ $actions.Add([PSCustomObject]@{
+ Phase = "export"
+ Item = $name
+ Source = $source
+ Destination = $destination
+ Status = $status
+ })
+}
+
+foreach ($name in $ExportDirectories) {
+ $source = Join-Path $sourceConfig $name
+ $destination = Join-Path $bundleConfig $name
+ $status = Copy-KnownItem -Source $source -Destination $destination -Overwrite $true
+ $actions.Add([PSCustomObject]@{
+ Phase = "export"
+ Item = $name
+ Source = $source
+ Destination = $destination
+ Status = $status
+ })
+}
+
+$nimbusConfig = ""
+if ($ImportToNimbus) {
+ $nimbusFallbackRoots = @(
+ "$env:ProgramFiles\Nimbus",
+ "${env:ProgramFiles(x86)}\Nimbus",
+ "$env:ProgramData\Nimbus",
+ "$env:LOCALAPPDATA\Nimbus",
+ "$env:APPDATA\Nimbus"
+ )
+
+ $nimbusConfig = Resolve-ConfigDirectory `
+ -ExplicitPath $NimbusConfigDir `
+ -ProductPattern "Nimbus|Vibepollo" `
+ -FallbackRoots $nimbusFallbackRoots
+
+ if ([string]::IsNullOrWhiteSpace($nimbusConfig)) {
+ if ([string]::IsNullOrWhiteSpace($NimbusConfigDir)) {
+ $nimbusConfig = Join-Path $env:ProgramFiles "Nimbus\config"
+ } else {
+ $nimbusConfig = $NimbusConfigDir
+ }
+ }
+
+ New-Item -ItemType Directory -Path $nimbusConfig -Force | Out-Null
+ $nimbusConfig = (Resolve-Path -LiteralPath $nimbusConfig).ProviderPath
+
+ $targetBackup = Join-Path $resolvedOutput "existing-nimbus-backup"
+ New-Item -ItemType Directory -Path $targetBackup -Force | Out-Null
+
+ foreach ($name in ($ImportFiles + $ImportDirectories)) {
+ $existingTarget = Join-Path $nimbusConfig $name
+ if (Test-Path -LiteralPath $existingTarget) {
+ $backupDestination = Join-Path $targetBackup $name
+ $backupStatus = Copy-KnownItem -Source $existingTarget -Destination $backupDestination -Overwrite $true
+ $actions.Add([PSCustomObject]@{
+ Phase = "target-backup"
+ Item = $name
+ Source = $existingTarget
+ Destination = $backupDestination
+ Status = $backupStatus
+ })
+ }
+ }
+
+ foreach ($name in $ImportFiles) {
+ $source = Join-Path $bundleConfig $name
+ $destination = Join-Path $nimbusConfig $name
+ $status = Copy-KnownItem -Source $source -Destination $destination -Overwrite ([bool]$Force)
+ $actions.Add([PSCustomObject]@{
+ Phase = "import"
+ Item = $name
+ Source = $source
+ Destination = $destination
+ Status = $status
+ })
+ }
+
+ foreach ($name in $ImportDirectories) {
+ $source = Join-Path $bundleConfig $name
+ $destination = Join-Path $nimbusConfig $name
+ $status = Copy-KnownItem -Source $source -Destination $destination -Overwrite ([bool]$Force)
+ $actions.Add([PSCustomObject]@{
+ Phase = "import"
+ Item = $name
+ Source = $source
+ Destination = $destination
+ Status = $status
+ })
+ }
+
+ if (-not $SkipCredentials) {
+ Repair-CredentialsAcl -ConfigDir $nimbusConfig
+ }
+}
+
+$manifest = [PSCustomObject]@{
+ Schema = "nimbus.apolloSwitchBundle.v1"
+ CapturedAt = (Get-Date).ToString("o")
+ SourceConfigDir = $sourceConfig
+ BundleDir = $resolvedOutput
+ BundleConfigDir = $bundleConfig
+ ImportToNimbus = [bool]$ImportToNimbus
+ NimbusConfigDir = $nimbusConfig
+ SkipCredentials = [bool]$SkipCredentials
+ Force = [bool]$Force
+ Sensitive = -not $SkipCredentials
+ Actions = @($actions.ToArray())
+ BundleInventory = @(Get-FileInventory -Root $bundleConfig)
+}
+
+$manifestPath = Join-Path $resolvedOutput "switch-bundle-manifest.json"
+$summaryPath = Join-Path $resolvedOutput "switch-bundle-summary.md"
+
+$manifest | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $manifestPath -Encoding UTF8
+
+$copied = @($actions | Where-Object { $_.Status -eq "copied" }).Count
+$skipped = @($actions | Where-Object { $_.Status -like "skipped*" }).Count
+$missing = @($actions | Where-Object { $_.Status -eq "missing" }).Count
+
+$summary = @(
+ "# Apollo To Nimbus Switch Bundle"
+ ""
+ "- Captured: $($manifest.CapturedAt)"
+ "- Source config: $sourceConfig"
+ "- Bundle: $resolvedOutput"
+ "- Imported to Nimbus: $([bool]$ImportToNimbus)"
+ "- Nimbus config: $nimbusConfig"
+ "- Includes credentials: $(-not $SkipCredentials)"
+ "- Copied: $copied"
+ "- Skipped: $skipped"
+ "- Missing: $missing"
+ ""
+ "This bundle may contain web UI credentials, paired-client state, private keys, and client certificates."
+ "Do not attach it to public issues or share it without reviewing the contents first."
+ ""
+ "Machine-readable manifest: switch-bundle-manifest.json"
+) -join [Environment]::NewLine
+
+$summary | Set-Content -LiteralPath $summaryPath -Encoding UTF8
+
+Write-Host "Apollo to Nimbus switch bundle written to:"
+Write-Host " $summaryPath"
+Write-Host " $manifestPath"
+if ($ImportToNimbus) {
+ Write-Host "Import target:"
+ Write-Host " $nimbusConfig"
+}
From 682cdc1495e80a785d99e93b3ccc37f3d2aa0828 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Sun, 24 May 2026 00:27:49 +1000
Subject: [PATCH 40/60] docs: record switch-test package candidate
---
docs/windows-installer-fixture.md | 18 +++++++++---------
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 10 +++++-----
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/docs/windows-installer-fixture.md b/docs/windows-installer-fixture.md
index a4e2826136..04bc28939a 100644
--- a/docs/windows-installer-fixture.md
+++ b/docs/windows-installer-fixture.md
@@ -29,13 +29,13 @@ flowchart TD
## Candidate Artifact
The current local package validation produced these artifacts from source commit
-`4f3411b2`. The documentation commit that records these hashes may be newer than
+`10ed2c32`. The documentation commit that records these hashes may be newer than
the validated source commit.
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,871,872 | `EEAD1749BA88032AFD09E7FBB1917B50DDA88F425059CEEDC18775ADE3028328` |
-| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,606,727 | `6E739CE9F56B11A0FD5B824E460AB389A0C61216FEE2CCE8DAA30E1E27F48D4E` |
+| `build/nimbus-package-validation/cpack_artifacts/NimbusSetup.exe` | 25,885,696 | `3CAA664566F29D988C959F87C4DC1519DB409E8BDF84752EF26C1D9ADA453A52` |
+| `build/nimbus-package-validation/cpack_artifacts/Nimbus.msi` | 25,619,015 | `F7B04CE0922FECC823CC363B4794DACDD90E92E10F6F70B388965B33A28F4D01` |
Before tagging `nimbus-v0.1.0-alpha.1`, either use these artifacts for fixture
testing or rebuild the package from the final release-prep commit and replace
@@ -47,8 +47,8 @@ Current artifact metadata:
| Field | Value |
| --- | --- |
| Bootstrapper product | `Nimbus Installer` |
-| File version | `0.0.0.44` |
-| Product version | `4f3411b2` |
+| File version | `0.0.0.53` |
+| Product version | `1.16.0-alpha.3-50-g10ed2c32` |
| Company | `Kuno Labs` |
| Signing | Unsigned; SignPath skipped because `SIGNPATH_API_TOKEN` is unset |
@@ -78,8 +78,8 @@ so user-facing version surfaces no longer look like an unversioned build.
Date: 2026-05-21
-Current candidate artifact: `NimbusSetup.exe` from source commit `4f3411b2`
-(`0.0.0.44`). The observations below were gathered during the maintainer VM
+Current candidate artifact: `NimbusSetup.exe` from source commit `10ed2c32`
+(`0.0.0.53`). The observations below were gathered during the maintainer VM
smoke loop on the immediately preceding candidate series. Screenshots and
fixture handoff folders are local validation evidence and are not committed to
the public repository.
@@ -93,7 +93,7 @@ Observed so far:
| Windows service after install | Observed compatibility pass | Service is running. Internal service name remains `ApolloService`; visible service description is `Nimbus Service`. |
| Web UI launch path | Observed pass | Tray context menu can open the local Web UI. Browser certificate warning is expected for the inherited local HTTPS flow. |
| Uninstall confirmation modal | Observed pass | Modal copy correctly describes uninstall options and factory-reset behavior. |
-| Uninstaller quick tips | Fixed, retest pending | An older candidate reused install/upgrade tips in uninstall mode. Fixed in `0af1f3b8`; retest with the current `0.0.0.44` candidate. |
+| Uninstaller quick tips | Fixed, retest pending | An older candidate reused install/upgrade tips in uninstall mode. Fixed in `0af1f3b8`; retest with the current `0.0.0.53` candidate. |
| Manual tray update check | Observed pass | Maintainer confirmed the `Check for Update` tray action shows visible feedback in the VM. |
| Compatible-client pairing | Observed pass | Artemis on Shield TV paired with the Nimbus VM host. |
| Compatible-client stream smoke | Observed pass | Artemis on Shield TV streamed from the Nimbus VM host and disconnected cleanly; no issues observed so far. |
@@ -104,7 +104,7 @@ Observed so far:
Still blocking the alpha gate:
-- Confirm the `0.0.0.44` uninstaller quick tips show uninstall-specific copy.
+- Confirm the `0.0.0.53` uninstaller quick tips show uninstall-specific copy.
- Confirm clicking the pairing notification scrolls directly to the Pair Client
section in the next candidate.
- Confirm the next candidate logs `NimbusDisplayRestore` and `Nimbus state file`
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index ad982f676b..2f14c5cb7c 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -99,12 +99,12 @@ Current source validation has passed after the UI and status-message rebrand:
portable binaries and the WiX ICE validation step runs outside the Codex
sandbox.
-Current local package artifacts from commit `4f3411b2`:
+Current local package artifacts from commit `10ed2c32`:
| Artifact | Size | SHA256 |
| --- | ---: | --- |
-| `NimbusSetup.exe` | 25,871,872 | `EEAD1749BA88032AFD09E7FBB1917B50DDA88F425059CEEDC18775ADE3028328` |
-| `Nimbus.msi` | 25,606,727 | `6E739CE9F56B11A0FD5B824E460AB389A0C61216FEE2CCE8DAA30E1E27F48D4E` |
+| `NimbusSetup.exe` | 25,885,696 | `3CAA664566F29D988C959F87C4DC1519DB409E8BDF84752EF26C1D9ADA453A52` |
+| `Nimbus.msi` | 25,619,015 | `F7B04CE0922FECC823CC363B4794DACDD90E92E10F6F70B388965B33A28F4D01` |
These are local validation artifacts, not release candidates, until the VM
fixture checks below are completed and recorded.
@@ -118,7 +118,7 @@ Partial manual VM observations from the previous candidate loop:
preserving the inherited internal `ApolloService` service name for this alpha.
- No Microsoft Defender warning was observed during the manual install smoke.
- The uninstaller quick-tip panel was fixed after VM feedback and still needs a
- retest with the `0.0.0.44` candidate.
+ retest with the `0.0.0.53` candidate.
- Manual tray update-check feedback is visible in the VM.
- Artemis on Shield TV can pair with the Nimbus VM host.
- Artemis on Shield TV can stream from the Nimbus VM host and disconnect
@@ -126,7 +126,7 @@ Partial manual VM observations from the previous candidate loop:
Pending before release:
-- Retest the `0.0.0.44` uninstaller quick-tip copy.
+- Retest the `0.0.0.53` uninstaller quick-tip copy.
- Uninstall and reinstall behavior.
- Retest the pairing notification deep link and runtime log-branding cleanup in
the next candidate build.
From bdce9c758b7fc1b2e24cabe6d21ed71de299c344 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Sun, 24 May 2026 22:06:36 +1000
Subject: [PATCH 41/60] fix: detect drive-root Apollo configs
---
docs/apollo-to-nimbus-switch.md | 10 ++++--
release_notes/drafts/nimbus-v0.1.0-alpha.1.md | 2 ++
scripts/collect_apollo_switch_bundle.ps1 | 33 +++++++++++++++++--
3 files changed, 39 insertions(+), 6 deletions(-)
diff --git a/docs/apollo-to-nimbus-switch.md b/docs/apollo-to-nimbus-switch.md
index f427d6bc12..927583d527 100644
--- a/docs/apollo-to-nimbus-switch.md
+++ b/docs/apollo-to-nimbus-switch.md
@@ -62,8 +62,9 @@ Run this from an elevated PowerShell window before uninstalling Apollo:
powershell -ExecutionPolicy Bypass -File .\scripts\collect_apollo_switch_bundle.ps1
```
-The script looks for Apollo in the registry and common install/config paths. It
-writes a timestamped bundle under `nimbus-switch-bundles/` with:
+The script looks for Apollo in the registry, common install/config paths, and
+drive-root portable installs such as `S:\Apollo\config`. It writes a
+timestamped bundle under `nimbus-switch-bundles/` with:
- `config/`: copied Apollo config files and folders.
- `switch-bundle-summary.md`: human-readable summary.
@@ -73,9 +74,12 @@ If Apollo uses a non-standard config path, pass it explicitly:
```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\collect_apollo_switch_bundle.ps1 `
- -SourceConfigDir "C:\Program Files\Apollo\config"
+ -SourceConfigDir "S:\Apollo\config"
```
+Keep old Sunshine backups, such as `S:\Sunshine`, separate from this Apollo
+switch bundle unless you are deliberately exporting Sunshine instead of Apollo.
+
## Import Into Nimbus
After installing Nimbus, stop the service before importing:
diff --git a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
index 2f14c5cb7c..ba11f04b94 100644
--- a/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
+++ b/release_notes/drafts/nimbus-v0.1.0-alpha.1.md
@@ -64,6 +64,8 @@ has wider testers.
- Added an Apollo-to-Nimbus switch bundle script and switch guide so existing
Apollo apps, host settings, credentials, paired clients, and covers can be
backed up and imported deliberately during alpha testing.
+- Improved the switch bundle source detection so drive-root Apollo installs such
+ as `S:\Apollo\config` are found without requiring an explicit source path.
## Compatibility Notes
diff --git a/scripts/collect_apollo_switch_bundle.ps1 b/scripts/collect_apollo_switch_bundle.ps1
index 3876865846..65f6af7f84 100644
--- a/scripts/collect_apollo_switch_bundle.ps1
+++ b/scripts/collect_apollo_switch_bundle.ps1
@@ -58,19 +58,45 @@ function Get-InstallLocationsFromRegistry {
function Test-ConfigCandidate {
param([string]$Path)
- if ([string]::IsNullOrWhiteSpace($Path) -or -not (Test-Path -LiteralPath $Path -PathType Container)) {
+ if ([string]::IsNullOrWhiteSpace($Path)) {
+ return $false
+ }
+
+ try {
+ if (-not (Test-Path -LiteralPath $Path -PathType Container -ErrorAction Stop)) {
+ return $false
+ }
+ }
+ catch {
return $false
}
foreach ($name in @("apps.json", "sunshine.conf", "sunshine_state.json", "credentials", "covers")) {
- if (Test-Path -LiteralPath (Join-Path $Path $name)) {
- return $true
+ try {
+ if (Test-Path -LiteralPath (Join-Path $Path $name) -ErrorAction Stop) {
+ return $true
+ }
+ }
+ catch {
+ continue
}
}
return $false
}
+function Get-DriveRootProductCandidates {
+ param([string[]]$ProductNames)
+
+ Get-PSDrive -PSProvider FileSystem |
+ Where-Object { -not [string]::IsNullOrWhiteSpace($_.Root) } |
+ ForEach-Object {
+ foreach ($productName in $ProductNames) {
+ Join-Path $_.Root $productName
+ }
+ }
+}
+
function Resolve-ConfigDirectory {
param(
[string]$ExplicitPath,
@@ -182,6 +208,7 @@ $apolloFallbackRoots = @(
"$env:LOCALAPPDATA\Apollo",
"$env:APPDATA\Apollo"
)
+$apolloFallbackRoots += Get-DriveRootProductCandidates -ProductNames @("Apollo")
$sourceConfig = Resolve-ConfigDirectory `
-ExplicitPath $SourceConfigDir `
From 213e2ff4e3697224f7ab90e8243a8303369c0776 Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Sun, 24 May 2026 22:17:13 +1000
Subject: [PATCH 42/60] chore: ignore local switch bundles
---
.gitignore | 3 +++
docs/apollo-to-nimbus-switch.md | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index f2e2183890..ec8c593a84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,9 @@
# VSCode IDE
.vscode/
+# Local switch/export bundles may contain credentials, certificates, and keys.
+nimbus-switch-bundles/
+
# build directories
build/
cmake-*/
diff --git a/docs/apollo-to-nimbus-switch.md b/docs/apollo-to-nimbus-switch.md
index 927583d527..30ae44b025 100644
--- a/docs/apollo-to-nimbus-switch.md
+++ b/docs/apollo-to-nimbus-switch.md
@@ -64,7 +64,7 @@ powershell -ExecutionPolicy Bypass -File .\scripts\collect_apollo_switch_bundle.
The script looks for Apollo in the registry, common install/config paths, and
drive-root portable installs such as `S:\Apollo\config`. It writes a
-timestamped bundle under `nimbus-switch-bundles/` with:
+timestamped, gitignored bundle under `nimbus-switch-bundles/` with:
- `config/`: copied Apollo config files and folders.
- `switch-bundle-summary.md`: human-readable summary.
From c5eb66acd72c05a0df325bff1aac2983e67ba07f Mon Sep 17 00:00:00 2001
From: ywkuno <21991205+ywkuno@users.noreply.github.com>
Date: Sun, 24 May 2026 22:55:57 +1000
Subject: [PATCH 43/60] feat: add Nimbus icon identity
---
cmake/compile_definitions/linux.cmake | 2 +-
cmake/compile_definitions/windows.cmake | 4 +-
cmake/packaging/common.cmake | 2 +-
cmake/packaging/linux.cmake | 22 +-
cmake/packaging/windows.cmake | 2 +-
cmake/packaging/windows_wix.cmake | 2 +-
cmake/targets/windows.cmake | 2 +-
nimbus.ico | Bin 0 -> 30143 bytes
nimbus.png | Bin 0 -> 13280 bytes
nimbus.svg | 14 +
.../bootstrapper/build_bootstrapper.ps1 | 2 +-
scripts/icons/README.md | 17 ++
scripts/icons/convert_and_pack.sh | 8 +-
scripts/icons/generate_nimbus_icon.ps1 | 242 ++++++++++++++++++
src/confighttp.cpp | 16 +-
src/system_tray.cpp | 16 +-
.../web/public/images/logo-nimbus-16.png | Bin 0 -> 800 bytes
.../web/public/images/logo-nimbus-45.png | Bin 0 -> 2193 bytes
.../assets/web/public/images/logo-nimbus.svg | 14 +
.../web/public/images/nimbus-locked-16.png | Bin 0 -> 828 bytes
.../web/public/images/nimbus-locked-45.png | Bin 0 -> 2476 bytes
.../web/public/images/nimbus-locked.ico | Bin 0 -> 35139 bytes
.../web/public/images/nimbus-locked.png | Bin 0 -> 15803 bytes
.../web/public/images/nimbus-locked.svg | 17 ++
.../web/public/images/nimbus-pausing-16.png | Bin 0 -> 836 bytes
.../web/public/images/nimbus-pausing-45.png | Bin 0 -> 2424 bytes
.../web/public/images/nimbus-pausing.ico | Bin 0 -> 34705 bytes
.../web/public/images/nimbus-pausing.png | Bin 0 -> 15704 bytes
.../web/public/images/nimbus-pausing.svg | 16 ++
.../web/public/images/nimbus-playing-16.png | Bin 0 -> 833 bytes
.../web/public/images/nimbus-playing-45.png | Bin 0 -> 2442 bytes
.../web/public/images/nimbus-playing.ico | Bin 0 -> 34639 bytes
.../web/public/images/nimbus-playing.png | Bin 0 -> 15489 bytes
.../web/public/images/nimbus-playing.svg | 16 ++
.../assets/web/public/images/nimbus.ico | Bin 0 -> 30143 bytes
.../assets/web/public/images/nimbus.svg | 18 +-
36 files changed, 389 insertions(+), 43 deletions(-)
create mode 100644 nimbus.ico
create mode 100644 nimbus.png
create mode 100644 nimbus.svg
create mode 100644 scripts/icons/README.md
create mode 100644 scripts/icons/generate_nimbus_icon.ps1
create mode 100644 src_assets/common/assets/web/public/images/logo-nimbus-16.png
create mode 100644 src_assets/common/assets/web/public/images/logo-nimbus-45.png
create mode 100644 src_assets/common/assets/web/public/images/logo-nimbus.svg
create mode 100644 src_assets/common/assets/web/public/images/nimbus-locked-16.png
create mode 100644 src_assets/common/assets/web/public/images/nimbus-locked-45.png
create mode 100644 src_assets/common/assets/web/public/images/nimbus-locked.ico
create mode 100644 src_assets/common/assets/web/public/images/nimbus-locked.png
create mode 100644 src_assets/common/assets/web/public/images/nimbus-locked.svg
create mode 100644 src_assets/common/assets/web/public/images/nimbus-pausing-16.png
create mode 100644 src_assets/common/assets/web/public/images/nimbus-pausing-45.png
create mode 100644 src_assets/common/assets/web/public/images/nimbus-pausing.ico
create mode 100644 src_assets/common/assets/web/public/images/nimbus-pausing.png
create mode 100644 src_assets/common/assets/web/public/images/nimbus-pausing.svg
create mode 100644 src_assets/common/assets/web/public/images/nimbus-playing-16.png
create mode 100644 src_assets/common/assets/web/public/images/nimbus-playing-45.png
create mode 100644 src_assets/common/assets/web/public/images/nimbus-playing.ico
create mode 100644 src_assets/common/assets/web/public/images/nimbus-playing.png
create mode 100644 src_assets/common/assets/web/public/images/nimbus-playing.svg
create mode 100644 src_assets/common/assets/web/public/images/nimbus.ico
diff --git a/cmake/compile_definitions/linux.cmake b/cmake/compile_definitions/linux.cmake
index da28b6249a..dd3ac50079 100644
--- a/cmake/compile_definitions/linux.cmake
+++ b/cmake/compile_definitions/linux.cmake
@@ -200,7 +200,7 @@ if(${SUNSHINE_ENABLE_TRAY})
if(${SUNSHINE_BUILD_FLATPAK})
set(SUNSHINE_TRAY_PREFIX "${PROJECT_FQDN}")
else()
- set(SUNSHINE_TRAY_PREFIX "apollo")
+ set(SUNSHINE_TRAY_PREFIX "nimbus")
endif()
list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_TRAY_PREFIX="${SUNSHINE_TRAY_PREFIX}")
else()
diff --git a/cmake/compile_definitions/windows.cmake b/cmake/compile_definitions/windows.cmake
index cf02c63c9f..043f424dd1 100644
--- a/cmake/compile_definitions/windows.cmake
+++ b/cmake/compile_definitions/windows.cmake
@@ -34,9 +34,9 @@ file(GLOB NVPREFS_FILES CONFIGURE_DEPENDS
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/include")
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/third-party/sudovda")
-# apollo icon
+# Nimbus icon
if(NOT DEFINED PROJECT_ICON_PATH)
- set(PROJECT_ICON_PATH "${CMAKE_SOURCE_DIR}/apollo.ico")
+ set(PROJECT_ICON_PATH "${CMAKE_SOURCE_DIR}/nimbus.ico")
endif()
list(APPEND SUNSHINE_DEFINITIONS PROJECT_APP_USER_MODEL_ID="${WINDOWS_APP_USER_MODEL_ID}")
diff --git a/cmake/packaging/common.cmake b/cmake/packaging/common.cmake
index b9690ea074..7b7e3b520d 100644
--- a/cmake/packaging/common.cmake
+++ b/cmake/packaging/common.cmake
@@ -13,7 +13,7 @@ set(CPACK_PACKAGE_CONTACT "https://github.com/kunolabs/Nimbus/issues")
set(CPACK_PACKAGE_DESCRIPTION ${CMAKE_PROJECT_DESCRIPTION})
set(CPACK_PACKAGE_HOMEPAGE_URL ${CMAKE_PROJECT_HOMEPAGE_URL})
set(CPACK_RESOURCE_FILE_LICENSE ${PROJECT_SOURCE_DIR}/LICENSE)
-set(CPACK_PACKAGE_ICON ${PROJECT_SOURCE_DIR}/sunshine.png)
+set(CPACK_PACKAGE_ICON ${PROJECT_SOURCE_DIR}/nimbus.png)
# Ensure the generated installer filename uses the branded name
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}")
set(CPACK_STRIP_FILES YES)
diff --git a/cmake/packaging/linux.cmake b/cmake/packaging/linux.cmake
index e59663bf97..d72e6667dc 100644
--- a/cmake/packaging/linux.cmake
+++ b/cmake/packaging/linux.cmake
@@ -98,10 +98,10 @@ set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OFF)
# application icon
if(NOT ${SUNSHINE_BUILD_FLATPAK})
- install(FILES "${CMAKE_SOURCE_DIR}/apollo.svg"
+ install(FILES "${CMAKE_SOURCE_DIR}/nimbus.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps")
else()
- install(FILES "${CMAKE_SOURCE_DIR}/apollo.svg"
+ install(FILES "${CMAKE_SOURCE_DIR}/nimbus.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps"
RENAME "${PROJECT_FQDN}.svg")
endif()
@@ -109,27 +109,27 @@ endif()
# tray icon
if(${SUNSHINE_TRAY} STREQUAL 1)
if(NOT ${SUNSHINE_BUILD_FLATPAK})
- install(FILES "${CMAKE_SOURCE_DIR}/apollo.svg"
+ install(FILES "${CMAKE_SOURCE_DIR}/nimbus.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status"
- RENAME "apollo-tray.svg")
- install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/apollo-playing.svg"
+ RENAME "nimbus-tray.svg")
+ install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/nimbus-playing.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status")
- install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/apollo-pausing.svg"
+ install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/nimbus-pausing.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status")
- install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/apollo-locked.svg"
+ install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/nimbus-locked.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status")
else()
# flatpak icons must be prefixed with the app id or they will not be included in the flatpak
- install(FILES "${CMAKE_SOURCE_DIR}/apollo.svg"
+ install(FILES "${CMAKE_SOURCE_DIR}/nimbus.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status"
RENAME "${PROJECT_FQDN}-tray.svg")
- install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/apollo-playing.svg"
+ install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/nimbus-playing.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status"
RENAME "${PROJECT_FQDN}-playing.svg")
- install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/apollo-pausing.svg"
+ install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/nimbus-pausing.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status"
RENAME "${PROJECT_FQDN}-pausing.svg")
- install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/apollo-locked.svg"
+ install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/nimbus-locked.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status"
RENAME "${PROJECT_FQDN}-locked.svg")
endif()
diff --git a/cmake/packaging/windows.cmake b/cmake/packaging/windows.cmake
index d829e5c316..7ae94af248 100644
--- a/cmake/packaging/windows.cmake
+++ b/cmake/packaging/windows.cmake
@@ -116,7 +116,7 @@ if(NOT EXISTS "${CMAKE_BINARY_DIR}/assets/shaders")
execute_process(COMMAND cmd.exe /c mklink /J "${shaders_in_build_dest_native}" "${shaders_in_build_src_native}")
endif()
-set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}\\\\apollo.ico")
+set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}\\\\nimbus.ico")
# The name of the directory that will be created in C:/Program Files/
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Nimbus")
diff --git a/cmake/packaging/windows_wix.cmake b/cmake/packaging/windows_wix.cmake
index 3571555ab9..b6ecdd477d 100644
--- a/cmake/packaging/windows_wix.cmake
+++ b/cmake/packaging/windows_wix.cmake
@@ -5,7 +5,7 @@
set(CPACK_GENERATOR "WIX")
# Product identity and visuals
-set(CPACK_WIX_PRODUCT_ICON "${CMAKE_SOURCE_DIR}/src_assets/common/assets/web/public/images/apollo.ico")
+set(CPACK_WIX_PRODUCT_ICON "${CMAKE_SOURCE_DIR}/src_assets/common/assets/web/public/images/nimbus.ico")
set(CPACK_WIX_PROGRAM_MENU_FOLDER "Nimbus")
# Stable Upgrade GUID to enable in-place upgrades
diff --git a/cmake/targets/windows.cmake b/cmake/targets/windows.cmake
index f2bd569d32..245e5a08b9 100644
--- a/cmake/targets/windows.cmake
+++ b/cmake/targets/windows.cmake
@@ -62,7 +62,7 @@ add_custom_command(
"${CMAKE_SOURCE_DIR}/packaging/windows/bootstrapper/VibeshineInstaller.cs"
"${CMAKE_SOURCE_DIR}/packaging/windows/bootstrapper/app.manifest"
"${CMAKE_SOURCE_DIR}/LICENSE"
- "${CMAKE_SOURCE_DIR}/apollo.ico"
+ "${CMAKE_SOURCE_DIR}/nimbus.ico"
generate_windows_versioninfo
COMMENT "Building lightweight Nimbus uninstaller UI"
)
diff --git a/nimbus.ico b/nimbus.ico
new file mode 100644
index 0000000000000000000000000000000000000000..a0bbff8549bc60b3b7e33027465cdcd88db4273b
GIT binary patch
literal 30143
zcmbTebx>SE*Ecu}I=Dk{*I>bYu;3Cj2_7uCyA2M3;6Z}BOK^AhKyVw}0t_x8u#@Nc
zYX92ZxAvW?nOo=f=|0`3kM*za9RL6UfCj+D1;DQ~02)L9ARGVykdpqF=0pYnisAQY
zX#Pv9q5uHD&;S4ymjBXYr~m*h4gkQ-{a-p6-gZI^0D!^&rMEBufIw;h00Q|h9SCnT
zVTTKVfBwmX@&W*xQUE}dhMGJUIvG0rHkP7-tS0;lpAi5T4K5Eref44rzaY43%1Z;P
zrzno#1d^4MD!kv1IE*J#_#6QsCxs8L004IXzc0eDW2rd+0Bls0mC_bc4@)vs&@v?*
zp009rovYoSTE3_>n5yB+NKZuilt!DdhYG(kF&dUmzG`ee>dJi0r>n`7_!$p`%CBr-
z4gxLoeQC%Kj&umkt`scVIi@1Bi
z$LQBbj{F51qDBEtkB=Rl`n#vtJj;6*7y*Gh)h1xY_vo&a#ioO?bOXmRk&0vCDoGfx
zY(rHta9$ZhmUcTMiEgF38cDyzglG`y2HF2m(EuH(KuO&f0!<&9@L8^lH0-!S*lNi7
z1|={GPCK~ic3cE{E*|Eg$TR(4-AF)V5l#(P0j3wUG%^WdeBWMjib=ha`3z
z739@_T^_{GBn(1(c@UcxzP7|Dp`A(4)qa_s=x=8FLHrnXZcEFT;hUen>31K~vt!lZ
zYO}~EklOHsw^W($X0j;H%p%4wsy-dAOERf~d?mH=A^iiQg)Rq@x+LC`+)+csP+zdB
zH7c%G18GX;X%sqL?VI+q8t|jGj9C(4Vo9=el77@+5z*t{qj5Ii)pSAan*$-F8e{X3
zaK%mU!+q`dxm*QvmS5+!FU`b5OOzc8YHh6iWudr5a}KA!OBNYhM|%`31v86Q1^g~Cw`
zWOxo4L6gW)Z2Y6(*8l6q{-wtt0(GsG%83bQ`-+@3Q^O4<*l}jMusd7J(b^7!tsYxm
zP~}m3b|PU4ggmKW<5E>P8GCX>o!)s3nfLKQ9d$^$VZe|cpQGli$srz9sjj**Bp=Ou
zC5U?~Xis>WBvxYz_bLEDQBF;^TG}M||G_`t9tt4+kAFZt#qZ(7|8M_5>i_2-3d&U}
z_9|L>6hj%mqoJMl=k{eRmA{DP9Q0YaLQFXbOXXyd3FDjd8u%bz4zHO4(zJeJ;YE)@
zO!wqcRY_9Q<1NMq?4bf?d{cu+H;ChzSN$@w8P|ZX)Ca#
z^`7Wpsx#&OX9T{cpUh%|U~&vFS7VUcj}QSOX&bg+
zzDCm72L5=fZ_=g}gHOeVdibakrL@^};1gk8rg}n&^nz_}t89dKKi%N`gX0-ic
z^3CCaUv?eOJ?^nMkgoezkfRO9_V&QbJ6k+749_W*j?tIxxK!`Pb757
z-P)fu7j5$Q!Fph>2CpBYWV~ZNGZ-VH_rQu{6qVQb`(V$&cPCZMMKpP|tI0in91QSL
zj%+RO3A@E;<`(}$@#0mIU|kbv{ULnHFDS6He#!k(nG`i3_)U!*cdE-tPufY|=@Byo
zJ6o2=M2+!dLdzdB7-}pAAYYP7Vkpt#8y-J(MhhF@miiSi=^g6X2qO!}Wc=}X@9WK7
zR5y1R!@(Bn@#od(l8p~ySpiIGYw2wfyLN#U}_}-fQy%yA*<$GVIDhko`G?+T?X)
zWPX8tcgxicxhHy!fBYt1su3;4;ZhL|q>DmRhS5A6EB;kQ?>-+2AWO{p1(qqgvLXi%
zUIWA*9#1#prM|lX&iJzp7&J8y+f}op#ea(XOgDUsNC%lEf*3Vu`c0#@hMWgs|kYGb4EUs&sHL-Ra
zX?41#V@*H9y>JrF}QeZ6Msf;F59Y29O
zryKG^8JkR?=I=xP$yOT->kl>)MBb|jPD`#T9jUFO&PsFZo$?=MuOmO`(i;$)XD1~n
z7t_5mFmH;#Wu{d69=V$-n@|`=!BW=R*M#^(=Uj|-e?Y6_8Zr8bLDkrpy_Lo9I52M`
zD0O6KF<1R>h?w957RgiGw&cq+t#8B@(U<=rTGGJVY5o%}U44A6|2NSRdHY|qd@tXb
z>Z_t^F=6W^DP-*xg^|rA^T2Rsdn7+|K85T+sqt})6zIJ26ro{EA%gx?
zUZ$+ju%ciR3F?kWWVA>H`JNaRq=^yf9`a?V{C+TXI%+^N@l(1;WYPp$Q;j6`jj1sm
zMzsev?3+85)sxI8V=@D7cIw~{7_{0)d6o9BVqPxDTlH!DR`=Zz%9B&ENhUZUCb3lc
zNEm&hP3L(ZuL`!&tQ{o&mP3Pu!*EM6(TrNR%2&MK9+!AzW2BNPhZ{2*E7!)w2LgCFtz{x`BZ&m>3Vce%<(}V@=v+=BU>rE
zw~&?J-mso)iy3OlP@hFWA6pxZYLj!dL3JZ9FkO68YTg+=$ogBRQ{D<@de@Y)3A)$&
z2jaEP7c}*3iT<9w-j_8GGdcFN^}tAdde8V3SFD6sdfdU(TBvj*a-G}_74XQ1x<#Qt
z{(7OlbmK}Gu_Pu|T;^QfSOrvK|5E;qEf_
zijk9GPqonF(XVOz^#%$8wOwq*sk`(YrQaDpZE(Omlu7Dc`
zHK?P{c-?TeMA^8vA#LIM>ac`X)%L_Xl!QTeJ953xcaaPOwk_NcKljJh>S1
z8^syc2-Rh?IE7NQq4ARALhMT6JP(p?I7wtrPKqSn%z8J|aebyrbC*^Cv)M_Kt
zobcGi=&+Bfxt!s79Yk?&hu46He4=0IAsbxoE3u?D$H^KCz1n%^&SO9Rd#6N16iZI0`cpY%
zZVW`_o!gv{%#iiYGC`j{zwH-YIxt(Xd6H
zgQMy2H#W6dK(F{35G$5(f7+Ba{+bc4Vbj+CXrS!b+<5joyvn|@IT{HysLea06*zP@?rRF>d5u3lb(cgnt6Ks{NW&7fJ2ryi`sX@?b-jPb971O
z>G`bOBGX@w{9wgm{>J_}s@S&worODMNu|TKHvh?5SwZE2w)>=n^_KQc)ft~gWoCKr
zK7nY7O{S6-YV=g=Ug_Du7#j%H&T5F?et?{Ai6o+?UGFz=;Y#VDNd2@e3tK
z$E9jU+j5S^qv}T5x=^N7eUD<@=Q8p&j)ra#XkoD`yOu2;`%t15c41hF$JsP2%refB
zmPutca7{WVKCEa}1>yUFJ3Bx(Vo5^pV#L@m#Sx)$u$g-4Klgd}j9E?KkLk$%%x7KN
zshb_k4mdW;5u$jdBC-c(Kc@dl7?@7^{NmDu9m&
zix861lT|VNVntsXr@CFukwiV2=GGS$c9{m6`P@Jv`j^Qi
zdLew^=l4|s?wAun$9lhq8r!rJ3e%AoJx*|^O%i}vy)3kC@CdPzJ{MP>-il0U%IS(C
zq{aJ0(uihn>_9I;f9>^`0)EfmA#t5xB~yEnPr7b&_AkubaYn%|))CZd*_z0W^EfTp
z7@-ANrk}|}T@*1ANs@OSckLx<+&%WLxDqn;C<*1sKV{-no_v}kGc>U%NP8H|$^E!+
zG&rhN@z7(*i96Li#mH4#i_^{HZS`H8GQh(bIP|mv5n8E|Hfi?!s54H1nb!33I{$Ko
zR4w5nVq;YVDq-(CJhiC`m
zIT|U2eEWQw-q9jRwd&j!N7J?m?Rf1TwR;ai5N*LgcIqP+oNXAj$?2028{^OuTj0bX
z==yYx9US0ytM$2_{Rz$;@!XUD_%%Riy1~ck%e45_Xe-C35
zbG2{HXsAeEpoB+Q8mm6uU_6R>;hjD*1dYDqP0iopLQLT7`$_8Du~L(E9e^E;iBl$B
z0iMk&F|`RILdZ_()GLw&6r|a3nq8Q!BPd>eLmXMhQU?HKdI#qN9Scb2!e!$1yw_j`
z%=%_y;bqrS^cMuhmt1U&@`~kZ5tfV?jH9jy@lX(%nn`s^!tfDNA5V23yXkkRLGgjz
zF7xN^&iy!Y&R-_nHCCH1A#_3_w53BJ2xuHhol!|E3gCUU(EK~?8b}Tzr6}R9i5Tjd
zq-F^(An0o;r3E;7_sAE2-k}$A`Hh_j(OwcC*&d>f+NPVB^vlg6=>K_PVepFuY3d_w
zkGC3HkuxK^U>6vtuBA+#kR)Ng4^aT0TPQY`Yi_$3(9;JI(hWUA8)vanFs3Og?lgw8
z+_3Q7mUw~jG7s#;?}np|pth2}s9V=YG?^u6CE8L+*1db(h8N_$*F?JS3}ijn`EE}o
zdWx|*31dBMtz`ry#QbBoW>bH)$#aoTX&q?V#v5rwT#<0@*_~*()p#Lzj&k}
z6t)bsC?gu17hutAmil06^{&b~!bTNUdoNCPFevR(ZQwnXXUR5bK>G>6^UW}_?6+kU
zr;iFDNxE4?als~*xgf^spUwD5ruQZk?XfJ4bfzx>p4b#7>Fy>YS+rxd>P9YBX)ZI&
z5%1kPr=z#&4g#ou_;bbhI<{RSw)+r$u#j@@Rf<|_2rqa2)KV&jx^2LP?Oh|0xFMEC
zVp#Wl90G~XT*bC1b9K3`h#2qeDgW`~{MDnUL-a_~nx}zw?+&+Er>BCGc&7h;8r^MF
zcEOj4%Rdq0=b=MCt~@s;dmY_A6l`|ca@T!cU%dQP_d?Fe)*PZ*;V`_BkSnBKaHJ+C
zruo^+(nPjC@4TgLPcimPacz0vCs)AZcROvmcIohbo;(CI74nO)INF
zGk^VlO|ieHOYrj~sF+{7phEcZ?cJM(hWo#dO)o(D05Q+PTO#fMA(O*lYXJ9uGPxe`
zA>x0N$**LO+InQe8FqCE-Z*jZkStLwcX`B6-hyEWbQM5!qH}
zSKKRR9Q05k*l_TW(DR8gkyC>cEkD{d7%Et+F4l4`dk`4#)atGetyG^qmfkO^K4-W_
zw7$992r9_nTS|J8d86{Cdo$g&>nf{tTKvwHDm>4q@p=6b^QNmg+Rr0{+<&6IQi5?U
zZCLA4h}ie_4(nctTb#~md}q^d)@GYAcJfAke!0i}eqmGNz~c<>?E$V9yQJ9GkWQC#
zm*{1FeluAzJXB{BOj$Al%L&Y&@yeNt(B8p0G?HnjmWf!%=cZBOnpRwIIq6*@lInV!9i@NIndjh1a3)>(M^hQw*$lMK(s$-l{?d96^QQgd+#lp>!TtYrK~=
zrFY4TVJ~|zsHs{`NN!Z=lDvZ5>XmVQm^!$YrI=}X=+C22d&N-MRHP`*SNMOg;>qW@
zd0%d%{C$1jq%NA?Hw!SarBt@;zexhC<9Hoq7VRho*^U*9w)LYfy0oU7l0FXTG}l9PPHx5+-*^l6B&lxOKid~6SbblB%|eLcBdUWvoj~Hd5-n@E`uo>bmJX;$!jnu&hLuT1=$(3Bm>_;!X`#2`sHev-d
zB1=PQWhFR1Ua`^bvGR0oAOBtZg0W$5irrE7C6C=s#$=gQmZBX^>wqy$q}$Z2^f;s`
z7gVq5DQ&6X&*o(fRZNSO>p9Tf44TZ?R
zShzlKGqyZ1i{bfARTQ;&zTjm{qePhcodfCdd|(u71n8N4PLe+A
zoHN~pXKD847Jv)q!#EMk50MZOkwVTGgQ3npI3J>-fDDZhn>mEp$x5a{7TC5MR%ZP0
zh3>Mqygm2D8~AY~;;?;JPsGU9Cmm@hQC`+rsPq8kQPS
zy@U2X56$^}W+K&slKZ_t2qe-M}C-;IC4q<@e7sCX852Q20E@y6Lbbq-bA3_z&
zcF~{m0s-$p%W&=tF_y$CQFd?U%Gw?bZP;Zk){L$Q+WX1|xKs>KbSVEo3C6VdUa)
z=7{86h(PvoCB8qt=HlOv8r%C-)Co;RX{_J+fb3<^y`ittKsVSfWEM_
zJoU?cHA{In1^RhdapOe+R1}mN;TYUh7eo&RNw)Uv*wFuEHk(YLqbfAqE||0Osu>TS
zg%7orkyo`1n(0jNPTH&zzAG%OF(-adU*(bb^~fK
zaFPtS$rhnUvhQ0(xpfTCJ!dTV8a1q*Mra|T+|oUvYxSl4`I#T
zprcBFeEZQFZZHg~DN(>Z_bS|zsGeQet&CE+dasr7^D@Ho>WQG;0RXwC^b$Tqfp)=6|*N*y)Y8K@_RS1gu+O
z%6kO8S}96au(6TUt@gltu!T7r7jAeF@s92Vp
zfLlp>NatpQA2j=tj*#bs21D^>bjz^7I7ojMyL5K*(?Z9b#g1M4S9^+MoW+GMt-`WW
zYi4!XCGB_$6X^ijostbD&h=R9+C*ELBf1Ccy2Op}%xaZe>N=Zp9O^q;8&-5mA)@}(
zTFH_N$v>MSgP8qTeg8vE0*1GP|5KBcTRU(3Z)y?@kAF3Zm(ghk$ca#gY`AKryvo4U
z(lU*9beAtlDmN+UW6kH2Il9mRj=1c7fL`EV9*OB3eNN?+GOB3?cQhaG^
zVbjczHeAs0RMsZcdq-QVf3x}MGnQ+-g$P{nJp-|2Gb`G
z$bb!zcP(_8y;aiO{IP4SxpY-`ONjv!JI8A*x61jO)p#B`?{~hUYbGO8l?^n`q4J(Z=d7~`OOi5o6zfWj>u4A#7F;Dd^1b+Xm^x37D=jXn*
zR0c2Qih%%c?qn9|)O_qUl3LkNn(&Pkin1;67;$DmI>^H-6HBzetfzgAJsmZDaz
zEFGs&t~W#y;qUKBD`7kXy;hivR9!=%K@5G1vWmeqtgpJvSXp7@wysPp?le145E%
zH+iH%-pvM-s~yJ=OC-1EUM^V6rHlPd8jgbbL_f-U(+*v$TP
zC*du0!P0iKzWZ)>*B*(w?l~Ll%dg6FziXaFj*ji2ryxRbmM-Y397{i(krs}W+sJ9Y
zefb=uC#!{?r&b}ov~W6^-QmFTXyTbKvKSE1(9515om)#N#p`}nRC>mICDxk$Rwl>6
zYw?Po3#F!ZDKCaY3YK-^<7I_<66J4Q4)WHMXYc6KoRCctM@?C$oD+L+L|d-4j1FwE
z*Y0Qkq?8-OB{%Y@y3V(42-6mSWqT4A>)~ZZ!Oi(uOh$)Z50X&cZj9JLS4{X=UUX39
zKb+qJ%;)niItWy|ha8S_@6Pviz@(T`-2dRsJ=W>>*-!_yTC!t4V9gZkyu5~eS$cDb
zZVNs^O$9uL+5E{N+u*jqqs#E15BQ^4D0ZW+XIJg_JG-Qlpwovs*vcLvQg+E4WQ9b?
zv5gn627HT6?PP`>Tz>ZUX-dmsCL4Cv8HmP1jzb$ToM8lPiE6DOc{`j%AFTIrJdge3
z1aq#*0F2i4W5TcH1MJQNnSll>^YBiI5|l3^YqT}q{vKE=d+d1b@+65KIh44tD0UFe
z3$hgN!YF(I_Ium@?x+ly$Lk5a-%qa@f9u9EMG0c73c`3X2CyX^Q
z`yLP;%=FI7!hpzaumkud99dmFr|tle#BbnIfI|F1kIPFJkY%TSUV+x2l7OjxbhvVk
ztZscS0&UxuA#w0jR5*G>jbUU*-uiaIkQ=KG@mKJ=4L|5;5A0F#)ZTTIXv_&B!iOfq
z$be?WO2H*%)&4b+00(dVrY}Lw;ycMEE^C7rH8DBZ{?6iY5KMd;>}g`*w%-pkOKb*v
z_J1}cw}#pEIvJdhxtTjXyBWN`A4CvydrfLh*W)MV+~clf*mgj5E_g$c2yrm7YnnXK
zTf)cxF3KWnh_qp2l4tLGJ0oleifIj!y#+9u9;|9G>$Las0+qawX3T7bVSJN6fTSQj
z6h;`xgu#uPlvs>N`1I2qAgJB{y&<{X^i#B=?2eJ3mrkDw9>N4mXdRTFo1FSss!%Qk48YmuHT`qP;+a2~z&-r5YyffCd{;YQx
zdCU4c0Rautx%Z^&mJVoM8c0zGE$hL9geyY0_g%OX<^_r&L
zfLLt)R(s7Wn(Ud+vZOmk`tUq
z(pFG%|K_6uDdWN1=<(=%9GGGM*8y
zEjoao-I*z~i3PM*eY0r>S!trXN1~egr!#4V2A2Kq{#sZj?0K&-g6TTg!jRUcm~%CW
z#j1`)+8!cU>z}Zg5uW6*Em%OQf3lSAe25Pj!6+SU7F3uPU&Vkf#iPL`I$13cyMX(k
zGENf{hU@F>YadBHNJ;3wpfJyR6^1+#RKf_?A%&EeM>$4qGMHQ(Sv;bX(Fxg!Q3$>n
zR!GT$-Wa)6pIxA3BX~r(QozuyWk!y_XUVX(QV6?V7QRTEaUya}69+Cnx8Xknjq~h2
zM4m=F{Dd6YUtb|2Qv7wQziiG58MzkUL-MNbwU;SEYbC%M#y1>|F+xc!)?S;pNV;>%
z3GxH7IA#SH6L+k5uw(8`O2ZYY<#D!gfP78}o_=wOz?xpT{qi0)1~e$-{^)P8@4ce(
zaF}#e2c2&U<4)e}Wi|=_6=aqoM#!dyy3XuT#|KE{+?35~dZAhd`(3*z
zOpImD;}-kzP$}zYDo0RPCH7;T&*3<$vamHI&o7;qXk7RMf(+xH0BP~MMEqN|?}
z4{Yc=LC+|=vlVMK{Mr@;Dtuz}Vm)#}?)XFS8OlFy6S0dy^
zf21YXei*Y;ak6}Mg;2y^luR_iEO4ENEZ$tg+^jN|A!Kd2a7p-ab~Zm;kKL1034}rHs
z{!`%hOPG%TZwh>3!v9m?XMr@d_1YjMHszK}84kBqACQ79^*m&e5Tw5Q<2lO^N+HP+
zdg2ReIFC!m{3Ip#YB^Jw8Rh-q*8q=YV%h=kBNeANQ&QTmw2pzoPsDOrt)?h+jItt9|t)s6Ow~P=Ccw
zRAeJrwW?*0LKNY*e?jjQFaB>aA~M;aEE1Upbl-DQ;vakx3YjPud|e8`=%|~{EB9X)
zY2Jk}IKiwGbP3}7=)S#;EwqkTBS_2ZMRL+kP$b}c7xEg5DaedlrU|_yo`N`uHM8HP
zm%kCX7JaaBabn=fR_f_1IHckKdx?4(+wRS_g!m5g=F|ITK0WVM);C1I#puEdc_S}X
zzn$};jLy^G7;H!Pb{1~MzC50Vcokawp%EA|7UM{8TwOZSedju9ssiLNN_NzFP|L%7
zfabFR@5+nyy<{W1ue(rJ<8pfMgdOKO9t2xW`UUw-dC81HC@OG`PtM`Stg=O=&OLOhL`SQU$zMhut
zYOn88SpvPrt>V?vBuLkqOM*^+76y^{c}`gz@x@}T1u9oBmHT!rq
zav8zCzJ8e6Qo!?CXxgCo^O%6vq_@%EZRMY8_Bo#=5NS-Ffv1SZc++*J@C0G7$GTPJ
zgS%F;T+g^$4VOvhZw)?@*B+&{&p0
zbNHn8=5b=heM%vxAI^J(1BPMd@19xW&nezva$XSOwzykSuhvfm*-o_taE(z@UcT!1
zu4}N{_&N0Cads_nHUH@+{ibj}(i+Brq(-J_`o!(zE2(y0@~r$hxrYJ;2|C5f@Z8h(
z_T?_&{%%{f`@9O5$HTO=qibY5hRoz4Fuyb*GGo
zJZo+so%2S6(-rA+7*t6ay~1@)1LN{y<@%00auTcUHX5D)@1kb;IzMY0j{Et_kQp6$
z8lP!o1+TrFk1;#2qJZaoCXW}3$U|>(AbAdwKBJ50SoGz#c1{e=`dtxI2ww
zc$iJL#^r7&?^~b@X$e83*h-17i3?4AA?aJV4smoRX^|zuv4u~44=V9Z51cz7|
z!@pdXz4OO>uJ`F>Y;$`*QiAw-o4f~>a84+O;5Q~p>vAGW@xu?ig}3ggN#boNK@N=We(Us-5eXK#)0PwBC38+Bj@sj6#LxHKi7=a)js
z!M(K!=T!#iKmKq!7n1G5tZ=)wYH+!I*}cpKKmOL8w(p~WRUHTChWVDt_^(ATx{BLm4yVQ`XUC}VL;M^36SQA4iQJ}(~fcV%Ncn}e*`?XAy(~gnv
zk#m5yDDQM45znF&HBtg(*~SA%#M)y#1nAh(oQ1vQ?G{t~!GFG}*@O=J#+ksjx>?UQ
z0+IC2*Fr{7pOf0AJ;^dee_P(K6(rZ*q!&0ncUSkHhr~fQLIV50ouBvqB$we7WnKH(PegClQNghNl497{npg0`4
zO8wY*EiX37@uigc86olBnmFkkUx$MRz&`33H9`J;W^0V={$!D&cc|wi$g#T{arD8}
zj%ky*DUE)alr`+@FJxnA2Q%%~-n8%~KYcvYR70d68-Otfz+?hQN##m?y}wt?9qGASHXuKsh|>>j$rTQFr#Aec*>&Bq1|s)rcuta
zZSqU~jF}sz4$!Ki%gOFuw5CFQ$NTq%kisWCG0oX`fkjUw4%EMe6
zsfAux6@-H25p|LNx*<8FV@xET;~UcR0met<`xb6bQUdQ$_}8Py+q~x|f6a^Q*U|DJ
zf~z+>knyZ_26pLNiB$j1sLG)9N_SenRZ}!LfZv&G9dP$sH)#(8v&ZGqIg#1#FDTY8
zb7#2G&yrW(h(92a%87wIm=ZuBW$uH8_s~*mrV9{pxDmrhc~{53$2-t{{mN_C1gUS2
zo@z`Eez2%3_49dGVyG-(gx1DV{P}d(6xbqpA5Z_0x(#STho<(rzRj;5I76G$y5c$Q
z@RM9>EeIi=aT@QnF}}De7(kpnU3s9aWdq)r!N_jK5L#{dg)k%ikd1zg3^8co14#T(
zsu&yA5l;e^&SHY^{3WulF4m^80Z}Ut5-mdu=!w&k5Eaaxy36I&mZi%hz(>9fh5$TL
zbU>@q5!?L`k-n-#^?o`D#Nh$6?w2?2)mlj=AU-~}KX?}d4XkJ&F?CXp2z3?VCI$rK
zwa62{m+SIIAWfMzI31tee;48J0oZx$M(J*|@7U8qAjCj}6#6*;&?tL5rT)qTB@k$s
z)w59VMx>+11;ru6MwjUo{xxOnG+QGiA20Eq_@`ONy+>0AeqG`~8vG1qwoo9Xu@FbV
z$fy=Iq&}A
z;)FO1kz!OD6^W47ouE&*2HK->zFTY~n)|Q5alHogT{;UddI8Yjs^bEfPb)J|q&TJn
z?#HdFZ!a>b8xFnEKHR?X+HJZ@R7af|qK8C%M~F{QNA2;{QT10fQ3H&GXK|%5=3s;G
zKgEjxwk{tGPEQiKqRI%!0KyL~DbtdG&{z{Fio*c6IKaHWI)rI__`z=uk%rwEpPdCz
z2lo@36(PrDQ!23YB(NpmN|~~oIc8q}Hl1Pf8bFMfs*YNlrVd~n*xO;k-a-%y&D{Qg
zOPnLa@mw3I&T^G%Pw;y47XaoH(cq`}8#50fKFQGrkTkyEo3l=Yn_bwTf;8@nJX!)Q
zeZvnIhKvH%?J7gqO_@d&}6pZvjoy<=}DIMy3JfI6~9U8p*s2rd$v
zN(-^}?v=W~_}lno-u2&TPKyqTe?J;sPGUeR{S?gLz2sNJI3gP|s$EUTf
z3!_Vm#v@HpN6mFa*O&AfmigG#0~i@AL3}^qT@aJ^3ZQl_f=LN_Q?j5njamEBfy*7t
z%BxG74BsdwRPg&Q2w*I7d>AX!du{>*7H>W$O$Oa|DQal1+IS#s2D}gyek*Nus^7~X
z0epDqL!@D$7Igeh1*Wqyjrh_t-G_G=@8|=tAJ|jgwgjO;YW+kYjG2OCq^)~jf6*E*
z_F)GE#^lxoygE1uy*$N{l#({(m6zZ=`c4AhFl|7QA23Z@%|OCojgJ+A&IDMm@Nq*L
zovFQdo?1jl&Ux0^o!I%k%OeigCgTMuxP1mNG9t(YVaU4F!9y~~l&j6Yx{+?J{sQhy
z@2>=)jinAu6aO;>g#dfegRgJiIt&8g&q7@sxBg{?vJBHpp*Pg5_j+UHnIM@lO}yhc
z_)Y;Zg(n&sc52Vx-w7ZA4>GQQOp&2rN|2_B|G8`CBHmcocutVaD!wjdXwmPykBw8k#Gz(
z=SlEjF$Ny`Qn(a*03!ED8d3%l61ApAfTvwvp?4*S7;@bA@hjOw5AKM&I$TVg#)%qS
zd;k}?$yJZSXhy}th*kJbRBVK6oUnD6cEe0*qB7IuU`=wC*`
z1_-*G$5TQ0196KFw|u9L{lhqiglwAY@++7KAoUPwwfsf`K^s3cuEKjCnZ`hZw?bK63o0IzLN?O&-3$Lj`Wol)qp4l|N?w4#?6B
z4>~Jo{qTf1QccI1gPj|4_4bvFC}0l0n()~YM6N-?7T6L0)ZJ`!EFeZM7aNl4M*yT@
zre3_dD#;*#cweTs`e$km%?0J6T_c&W07d@e)MKevSn!Q8nBo@&@b2-t{&7Ph=n*Xk
zR0lruANaa(;{sgN<&nJkl_SSJDHnSLAvW9apdVVZS^=z$_uF^oD8YStcTGS;S2gQ}
z^cI*)*ONn9eZhYW51t2<5EUZ0MctS23IhWFWxsT0k6(D&uVNwcfZu3`a8Dy4g?k1Q
zszww-;YS0BPOEMTiV&V)75M8q=09nd1O1e26skn;n4JO6Hv9R%JQv^e-l#6bWu7AY}+N7B>}9@bwBBe+KOC
zW>ED=p8_gr13%wYyP6~4IC`K>0QX`nj?q-mOn#OdZC@G=n*rGG;W0}hf8_flo?VQ}
zo|rp8H+k9)>NZ3#<%CTnbrG{yj`ppwp_d_iGGVUzT
z2R8uHF0Xz|=0zVj3n~R7vy^*3SrRaEw3LQ(GZe0^Va9d(ny$fw$~aeQ!{XhYCvnz?
z2?5UiK3w|GpHF5VcrkA-u4?XjrbH83;I8(~50Qq8n#7H6uEI-lOpfvyakht+JE_zU
z#ZPrO*RJ+XHGI!-RXG3VN2x2X(0vg>>bXb&f|m{qJ$HfW5>Kpqfxn7}OzKZtR%2({>oPopm`-mW9R0ZxIS{kbjvorz~
z;UWX|gT`GxS~sI5il`+&jVh)AFh~6P^4-|gu
zf3){CJ>4&%