Skip to content

feat(ui): WebGL ambient background with day/night crossfade#386

Open
patschmittdev wants to merge 1 commit into
refactor/ui-foundationfrom
feat/webgl-ambient
Open

feat(ui): WebGL ambient background with day/night crossfade#386
patschmittdev wants to merge 1 commit into
refactor/ui-foundationfrom
feat/webgl-ambient

Conversation

@patschmittdev

Copy link
Copy Markdown
Collaborator

Summary

Adds a full-viewport WebGL ambient background to the app shell. It crossfades between a deep-forest night palette and a near-white day palette whenever the theme flips, and gently breathes the genesis aurora while an agent is streaming. The render loop runs only during the ~450ms theme morph and the activity breathe, then parks, so an idle window costs nothing. When WebGL is unavailable it falls back to a static CSS .app-ambient gradient, and it honors prefers-reduced-motion.

Changes

  • AmbientCanvas (AmbientCanvas.tsx): owns the GL context, the theme observer (watches the .dark class), and a parked rAF loop; caps device-pixel-ratio at 1.5; disposes safely under React StrictMode.
  • ambientScene (ambientScene.ts): pure shader + transition math (THEME_MS, vertex/fragment shaders, easeInOut, themeTarget), unit-tested in jsdom.
  • AppShell: mounts the canvas behind a z-10 content layer and drives the breathe from streamingByMind / a2aStreamingByMind.
  • index.css: .app-ambient static fallback gradient (self-contained oklch, no token dependencies).
  • env.d.ts: adds a vite/client reference so the import.meta.hot HMR block type-checks under the root tsconfig.
  • tsconfig.base.json: module: commonjs -> esnext. Required for import.meta to be legal under tsc --noEmit, and commonjs already conflicted with the moduleResolution: bundler set in the same file. tsc is --noEmit only here (Vite/esbuild own all emit), so this affects type-checking semantics, not output.

Test evidence

  • npm run lint: clean (tsc + eslint + dependency-cruiser 515 modules / 0 violations + yaml + markdown).
  • npm run typecheck: clean (exit 0).
  • npm test: 2001 passed / 1 failed. The single failure is MindProfileService > rejects symlinked profile files, which fails at fs.symlinkSync(...) with EPERM: operation not permitted. That is a Windows symlink-privilege limitation (requires Developer Mode), not a test assertion. The file is untouched by this branch and the test passes in CI on Linux.

Notes

  • No linked issue (feature initiated directly).
  • No SDK, server, or packaging surface is touched, so those smoke tests were not required.

Add a full-viewport WebGL ambient background that crossfades between a
deep-forest night palette and a near-white day palette whenever the
document theme flips, and gently breathes the genesis aurora while an
agent is streaming. The render loop runs only during the ~450ms theme
morph and the activity breathe, then parks, so an idle window costs
nothing. Falls back to a static CSS .app-ambient gradient when WebGL is
unavailable, and honors prefers-reduced-motion.

- AmbientCanvas owns the GL context, theme observer, and parked rAF loop;
  ambientScene holds the shader and transition math (pure, unit-tested).
- AppShell mounts the canvas behind a z-10 content layer and drives the
  breathe from streamingByMind / a2aStreamingByMind.
- Align tsconfig.base.json module to esnext (tsc is --noEmit only; Vite
  owns emit) so the import.meta.hot HMR block type-checks under the root
  tsconfig.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant