Files
SilverMetal/windows/docs/superpowers/specs/2026-06-09-first-boot-branding-design.md
sysadmin 66e7fd4ae8 docs(windows): first-boot experience & branding design spec
Design for SilverMetal Windows first-boot: declarative branding build
(4 layers baked offline into the WIM, shared dual-mode module), hardened
onboarding kiosk (Shell Launcher v2 + Keyboard Filter for the one-time
sm-bootstrap session), and the Hybrid fullscreen glass-card presentation
for the Welcome app. Fills the empty Invoke-Brand stub (M4 branding).

Approved in brainstorming. Next: writing-plans.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 13:53:58 +01:00

11 KiB

SilverMetal Windows — First-Boot Experience & Branding

Status: design — 2026-06-09. Approved in brainstorming. Fills the Invoke-Brand stub in installer/build.ps1 (M4 branding milestone) and adds the hardened onboarding kiosk + branded first-boot presentation. Bound by ../../../iso-builder.md, ../../../hardening-spec.md, and the product principles in ../../../../docs/.

1. Goal

Give SilverMetal Windows one cohesive, declaratively-built identity across every surface a user sees from power-on to desktop, and present the existing SilverOS Welcome onboarding wizard as a hardened, escape-proof, branded first-boot experience.

Everything is baked declaratively — offline registry/file servicing of the WIM in build.ps1 plus a SYSTEM configuration step at end-of-setup. No VM capture / golden-image (that idea remains parked).

2. Scope — three components, one initiative

# Component Where it runs
A Declarative branding — the four brand layers Offline (WIM) and online (self-apply) — shared module
B Hardened kiosk — Shell Launcher v2 + Keyboard Filter for the one-time sm-bootstrap session Build / OOBE path only
C First-boot presentation — Welcome app as fullscreen Hybrid glass card MAUI Welcome app

Out of scope: renaming the SilverOS.* app/namespace/paths to SilverMetal (tracked as a separate follow-up); a graphical OEM pre-boot/boot-logo splash (Secure Boot — out, per earlier brainstorm); bit-identical reproducibility (non-goal per iso-builder.md §5).

3. Decisions locked in brainstorming

  • Presentation: Hybrid — fullscreen branded backdrop + centered frosted-glass card.
  • Kiosk: hardened via Shell Launcher v2 (per-user → only sm-bootstrap), escapes disabled.
  • Branding: all four layers — BitLocker pre-boot message, lock/sign-in, desktop wallpaper+theme, OEM About. Custom bootloader / firmware logo OUT (Secure Boot).
  • Build: declarative (build.ps1 + offline registry). VM used only to design/verify visuals.
  • Aesthetic: dark "void" canvas, cyan (#00d4ff) core mark, teal-green (#00e5a0) secondary. Mockup: .superpowers/mockups/02-branding-layers.html and 01-presentation-model.html.
  • Name shown to users: SilverMetal Windows on every branding surface. (The Enhanced line is hardened Windows, not our own OS, so "SilverOS" would overclaim. The SilverOS.* app strings are working-title leftovers → separate rename follow-up.)
  • Content: support URL = https://silverlabs.uk (until a dedicated domain is locked); OEM Model = generic SilverMetal Windows; BitLocker recovery message = minimal, URL-only.
  • Code structure: split — shared dual-mode branding module + build-only kiosk.

4. Component A — Declarative branding (windows/branding/)

A shared, dual-mode module, mirroring the hardening/ "write once, used by ISO + self-apply" pattern.

windows/branding/
├── Apply-Branding.ps1        # -Mode Offline -MountPath <wim mount> | -Mode Online
├── branding.manifest.json    # all strings (names, URLs, OEM fields) — single source of truth
├── assets/
│   ├── lockscreen.jpg
│   ├── wallpaper.jpg
│   ├── oemlogo.bmp           # ~120x120 OEM About logo
│   └── SilverMetal.theme     # dark + cyan accent .theme
└── README.md
  • Offline mode: reg load the mounted image's SOFTWARE and C:\Users\Default\NTUSER.DAT hives, write values, reg unload (with the [gc]::Collect() + sleep guard already used elsewhere in build.ps1). Stage asset files into the mounted image.
  • Online mode: write live HKLM / default-user hive and copy assets to the running system. Same value set both ways.

Layers, mechanism, lock policy

Layer Registry / file Locked?
1 · BitLocker pre-boot SOFTWARE\Policies\Microsoft\FVE — pre-boot recovery message + URL policy values. Message ≈ "SilverMetal Windows. Locked out? silverlabs.uk". n/a (firmware)
2 · Lock / sign-in SOFTWARE\…\PersonalizationCSP lock-screen image (per-device reliable path) and SOFTWARE\Policies\Microsoft\Windows\Personalization\NoChangingLockScreen=1. Stage lockscreen.jpg to C:\Windows\Web\Screen\SilverMetal\. Locked
3 · Wallpaper + theme default-user NTUSER.DAT: Control Panel\Desktop\WallPaper (+ WallpaperStyle), dark mode (…\Themes\Personalize\AppsUseLightTheme=0, SystemUsesLightTheme=0), cyan accent. Stage wallpaper.jpg + SilverMetal.theme. Applies to every new account incl. the real end user. Changeable
4 · OEM About SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation: Manufacturer=SilverLABS, Model=SilverMetal Windows, SupportURL=https://silverlabs.uk, Logo=<oemlogo.bmp path>. n/a

Honest limitation — BitLocker pre-boot (Layer 1)

Only the BitLocker recovery screen's message + URL are customizable. The normal PIN-entry screen text ("Enter the PIN to unlock this drive") is fixed Windows UI and cannot be branded. The mockup's branded PIN title is aspirational; Layer 1's real deliverable is the recovery message + URL only. Exact FVE value names are pinned during implementation (the M1 hardening 02-data-at-rest.ps1 already touches FVE for PIN enrolment).

5. Component B — Hardened kiosk (build-only)

Locks the ephemeral sm-bootstrap onboarding session so the user cannot escape the wizard. The sm-bootstrap account, AutoLogon, and teardown already exist (autounattend.xml, SetupComplete.cmd, the Welcome app's ApplyService).

Offline (in build.ps1)

  • DISM /Enable-Feature /All for Client-EmbeddedShellLauncher (Shell Launcher v2) and Client-KeyboardFilter, applied to the mounted WIM. (Both ship in IoT Enterprise LTSC.)
  • Stage windows/installer/oem/Configure-Kiosk.ps1 into C:\Windows\Setup\Scripts\.

At end-of-setup (SetupComplete.cmd, runs as SYSTEM, after accounts exist, before first logon)

Configure-Kiosk.ps1:

  • Shell Launcher v2 (WMI WESL_UserSetting, online-only — hence configured here, not offline): default shell = explorer.exe; sm-bootstrap's shell = a small launcher that starts the Welcome app elevated (reuses the baked UAC auto-approve: ConsentPromptBehaviorAdmin=0). With no Explorer in that session there is no taskbar and no Start menu — the escape the operator saw is structurally gone.
  • Keyboard Filter (WMI WEKF_PredefinedKey / WEKF_Settings): block Win, Win+L, Ctrl+Esc, and similar shell hotkeys; DisableKeyboardFilterForAdministrators=false.
  • Security-screen / escape policies: DisableTaskMgr=1, DisableLockWorkstation=1, hide fast-user-switching and Log off. Applied scoped to the sm-bootstrap session and reverted at teardown (so the real user is unaffected).

Interaction with the existing flow

  • The autounattend.xml FirstLogonCommands app-launch is now redundant and removed — Shell Launcher launches the Welcome app as the session shell.
  • SetupComplete.cmd keeps its existing "defer hardening to Welcome when the app is present" branch; it gains the Configure-Kiosk.ps1 call.

Teardown (Welcome app ApplyService, on wizard success)

Already deletes sm-bootstrap + removes AutoLogon. Adds: remove the sm-bootstrap WESL custom-shell entry, revert the escape policies, (optionally clear Keyboard Filter rules). The features remain enabled but inert. The real end-user account then logs in to a normal, branded Explorer desktop.

6. Component C — First-boot presentation (MAUI Welcome app)

The Welcome app (windows/welcome/src/SilverOS.Welcome.App) is MAUI Blazor (WebView2). Today its window is the plain default and MainLayout is the stock template.

Native — window chrome

In the Windows lifecycle handler, customize the WinUI AppWindow:

  • OverlappedPresenter with border + title bar off, not resizable / minimizable / maximizable; use the FullScreen presenter so it covers the whole display.
  • Non-closable (suppress/ignore close); Alt+F4 is additionally blocked by the Keyboard Filter. This is the only native requirement — it removes the title bar and makes the app own the screen.

Visual — Blazor + CSS only

The Hybrid look (full-bleed branded backdrop + centered frosted-glass card) is rendered entirely in the WebView with CSS (backdrop-filter: blur(...) over the in-WebView wall), exactly as the mockup demonstrates. No OS-level Mica/Acrylic — in a Shell-Launcher kiosk there is no desktop behind the app to blur, so OS backdrop buys nothing.

Work: restyle MainLayout and the wizard step shell from the stock MAUI template to the brand identity — branded backdrop, centered glass card, step rail, cyan/teal accents, the type and motion direction from the SilverLABS aesthetic. The step components' logic is unchanged.

7. Build-flow wiring — what changes

  1. installer/build.ps1 Invoke-Brand → call branding\Apply-Branding.ps1 -Mode Offline -MountPath $mount and stage assets (inside the existing WIM-mounted block).
  2. installer/build.ps1 → new offline step: enable Shell Launcher + Keyboard Filter features; stage Configure-Kiosk.ps1.
  3. installer/oem/SetupComplete.cmd → invoke Configure-Kiosk.ps1 before first logon.
  4. installer/autounattend/autounattend.xml → remove the FirstLogonCommands Welcome launch.
  5. welcome/... → fullscreen borderless window + Hybrid CSS shell; ApplyService → kiosk teardown.

8. Testing

  • Branding module: Pester tests for Apply-Branding.ps1 — offline (load a throwaway hive into a temp mount, apply, assert each value + asset staged) and online (apply, read back, revert). Runs on the Windows runner; no hardware needed.
  • Kiosk + presentation: the existing VM e2e harness (SLAB01 VM 102, _stageiso.py / _pverun.py / _shot.py). Boot the built ISO → assert: no taskbar / Start in the bootstrap session, Task Manager / Win+L / Ctrl+Alt+Del options blocked, the glass card is fullscreen, the wizard completes → real user logs into a branded Explorer desktop with wallpaper, accent, locked lock-screen, and correct OEM About.
  • Honest scope: per iso-builder.md §5, "reproducible" = pinned inputs + recorded tool versions + output SHA-256 + SBOM; bit-identical rebuild stays a documented stretch goal.

9. Open items (resolve during implementation, not blocking)

  1. Pin exact FVE pre-boot recovery-message value names against the base media.
  2. Confirm PersonalizationCSP vs Policies\…\Personalization\LockScreenImage reliability on IoT Enterprise LTSC 24H2/25H2; pick the one that survives a clean OOBE.
  3. Decide whether Configure-Kiosk.ps1 sets the sm-bootstrap shell to the app directly (with requireAdministrator manifest) or to an elevating launcher script — pick the robust one during the elevation spike.
  4. Final logo asset (oemlogo.bmp, lock-screen, wallpaper) — placeholder void/cyan mark used until brand identity is finalized (shared/branding/README.md is still "to be defined").
  5. Separate follow-up: rename SilverOS.* app / namespace / install path to SilverMetal.