Files
SnowLuma/packages/webui/INTEGRATIONS.md
T
TanTan fa9c73363d
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
SnowLuma v2.4.2 source snapshot
2026-11-13 09:02:00 +08:00

6.1 KiB

Host appearance overlays

Set SNOWLUMA_WEBUI_TARGET=maibot on the SnowLuma process to use MaiBot's millennium appearance. The same release bundle supports standalone and embedded deployments. An unset or empty value keeps the existing SnowLuma experience; unknown values fail WebUI startup with an explicit diagnostic.

This first adapter implements millennium only, in light and dark modes. Other MaiBot styles are not implemented. There is no new appearance selector in SnowLuma. The host owns theme changes; existing theme controls are unavailable while managed, and the settings page explains which preferences are preserved.

Runtime and ownership

  1. Core reads the environment at startup. Static document delivery injects a validated, public JSON bootstrap into /, /index.html and SPA fallback documents. Documents use Cache-Control: no-store. No secrets or arbitrary environment variables reach the browser.
  2. Frontend bootstrap loads only the selected target's assets before mounting React. Standalone deployments load no target stylesheet, font or host listener. Vite development serves the same bootstrap when its process has the environment variable; production builds remain neutral.
  3. ThemeContext keeps savedAppearance separate from effective appearance. Only saved preferences enter localStorage or config/ui.json. Target updates never invoke the persistence API.
  4. The target owns colors, fonts, radius, wallpaper, CSS variable overrides, custom CSS and custom cursor presentation. These saved values are preserved but suspended. UI scale, density, motion/accessibility, navigation layout and data preferences remain available. Safe-mode restrictions still apply when returning to native appearance.
  5. A single layout effect applies effective appearance. Changes do not reload the document, change React keys or restart sessions. All target rules are scoped to html[data-webui-target], including portals under body.

Host protocol, version 1

The contract lives in common/webui-target.ts. The deployment environment is an opt-in, not a live transport. Existing launchers need to implement the sender below; merely setting the environment variable cannot convey another process's current theme.

A same-document embedding bridge (for example Electron executeJavaScript) publishes the latest snapshot before dispatching the event:

const appearance = {
    version: 1,
    target: 'maibot',
    style: 'millennium',
    mode: 'dark', // 'light' | 'dark' | 'system'
};
window.__SNOWLUMA_HOST_APPEARANCE__ = appearance;
window.dispatchEvent(new CustomEvent('snowluma:host-appearance', { detail: appearance }));

The snapshot handles messages sent before React or the lazy asset loader is ready. Publish on each guest dom-ready and whenever the host's resolved brightness changes. A host that already follows MaiBot should forward its own resolved light/dark state; this avoids competing sources of truth. Validate the guest's expected origin before injecting, serialize values with JSON.stringify, and do not enable Node integration in the guest.

Send { version: 1, target: null } using the same mechanism to release the override for the current document. The original appearance returns immediately. The opted-in document keeps its host subscription so the host can reapply the target later. Listeners are released on provider unmount. This does not change the startup environment or enable a target in a standalone deployment.

The current adapter starts with millennium and system brightness before a host snapshot arrives. The last valid snapshot remains active if the host stops sending. Snapshots are not persisted or shared across origins/tabs. A reload requires the host to publish again. Unsupported versions, targets, styles or modes are rejected with [SnowLuma appearance] console diagnostics; the previous valid snapshot remains. The host cannot supply CSS, URLs or executable content through this protocol. No unauthenticated HTTP write endpoint is introduced.

Adding a target

  • Add its identifier, styles and default style to WEBUI_TARGETS in the shared contract. Keep validation at this boundary; do not accept arbitrary strings.
  • Add one lazy loader to the exhaustive frontend registry. Implement a pure saved-to-effective resolver and scoped stylesheet under src/appearance/targets. Keep any fonts local with their redistribution license.
  • Use semantic color variables, shared component classes and neutral data-ui-surface markers. Do not add target-name checks to business pages.
  • Never persist resolved overrides, mutate saved preferences, introduce a second DOM theme writer, or remount the application to switch presentation.
  • Test default asset/listener isolation, initial document routes, malformed messages, rapid updates, cleanup and exact restoration of saved preferences. Verify forms, focus, scroll, portals and mobile layout with an isolated backend. Electron integration needs a separate real-host check.

Sources and checks

The adapter follows the main MaiBot repository's millennium stylesheet, not the archived standalone WebUI. Colors/materials also match the OneKey shell. The bundled Jersey 20 font is from that MaiBot revision, copyright The Soft Type Project Authors, under the SIL Open Font License. Its license is emitted alongside the font in production assets.

Focused checks (from the repository root):

pnpm --filter @snowluma/common exec vitest run tests/webui-target.test.ts
pnpm --filter @snowluma/core exec vitest run tests/webui-static-frontend.test.ts
pnpm --filter webui exec vitest run tests/target-appearance.test.ts

Run the normal workspace checks from AGENTS.md before handing off changes.