diff --git a/desktop/index.html b/desktop/index.html
index a2073d47f..31d90dc4d 100644
--- a/desktop/index.html
+++ b/desktop/index.html
@@ -5,6 +5,19 @@
+
+
diff --git a/desktop/src-tauri/tauri.conf.json b/desktop/src-tauri/tauri.conf.json
index 42392149a..83ef281d5 100644
--- a/desktop/src-tauri/tauri.conf.json
+++ b/desktop/src-tauri/tauri.conf.json
@@ -21,6 +21,7 @@
"height": 600,
"maximized": true,
"visible": false,
+ "backgroundColor": "#000000",
"titleBarStyle": "Overlay",
"hiddenTitle": true,
"dragDropEnabled": false,
diff --git a/desktop/src/app/App.tsx b/desktop/src/app/App.tsx
index 86bce8376..c3624af24 100644
--- a/desktop/src/app/App.tsx
+++ b/desktop/src/app/App.tsx
@@ -12,7 +12,6 @@ import {
} from "react";
import { router } from "@/app/router";
-import { ThemeGrainientBackground } from "@/app/ThemeGrainientBackground";
import { useReloadShortcut } from "@/app/useReloadShortcut";
import { useAppOnboardingState } from "@/features/onboarding/hooks";
import { OnboardingSlideTransition } from "@/features/onboarding/ui/OnboardingSlideTransition";
@@ -27,31 +26,26 @@ import { isSharedIdentity as isSharedIdentityCmd } from "@/shared/api/tauri";
import { listenForDeepLinks } from "@/shared/deep-link";
import { useSystemColorScheme } from "@/shared/theme/useSystemColorScheme";
import { Button } from "@/shared/ui/button";
+import { BuzzMark } from "@/shared/ui/buzz-logo/BuzzMark";
import { Spinner } from "@/shared/ui/spinner";
import { StartupWindowDragRegion } from "@/shared/ui/StartupWindowDragRegion";
import { StepProgress } from "@/shared/ui/step-progress";
const LOADING_TEXT = "Setting up your workspace...";
+// Cold boot gate: a plain static Buzz mark (#D7D72E) on solid black. No
+// animation machinery, no gradient — the mark must paint complete on the very
+// first frame, even in webviews that render before scripting or SMIL start.
function AppLoadingGate() {
return (
-
-
-
- {LOADING_TEXT}
-
- {LOADING_TEXT}
-
-
+ {LOADING_TEXT}
+
);
}
diff --git a/desktop/src/app/ThemeGrainientBackground.tsx b/desktop/src/app/ThemeGrainientBackground.tsx
deleted file mode 100644
index f9a81ef4b..000000000
--- a/desktop/src/app/ThemeGrainientBackground.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-export function ThemeGrainientBackground() {
- return (
-
- );
-}
diff --git a/desktop/src/shared/styles/globals/animations.css b/desktop/src/shared/styles/globals/animations.css
index 3cc935ec4..a057a55c5 100644
--- a/desktop/src/shared/styles/globals/animations.css
+++ b/desktop/src/shared/styles/globals/animations.css
@@ -338,234 +338,6 @@
}
}
-@property --buzz-grainient-x-0 {
- syntax: "";
- inherits: false;
- initial-value: 85%;
-}
-
-@property --buzz-grainient-y-0 {
- syntax: "";
- inherits: false;
- initial-value: 80%;
-}
-
-@property --buzz-grainient-x-1 {
- syntax: "";
- inherits: false;
- initial-value: 60%;
-}
-
-@property --buzz-grainient-y-1 {
- syntax: "";
- inherits: false;
- initial-value: 24%;
-}
-
-@property --buzz-grainient-x-2 {
- syntax: "";
- inherits: false;
- initial-value: 13%;
-}
-
-@property --buzz-grainient-y-2 {
- syntax: "";
- inherits: false;
- initial-value: 82%;
-}
-
-@property --buzz-grainient-x-3 {
- syntax: "";
- inherits: false;
- initial-value: 24%;
-}
-
-@property --buzz-grainient-y-3 {
- syntax: "";
- inherits: false;
- initial-value: 7%;
-}
-
-.buzz-setup-loading-shell {
- --buzz-grainient-alpha-strong: 0.46;
- --buzz-grainient-alpha-medium: 0.34;
- --buzz-grainient-alpha-soft: 0.24;
- --buzz-setup-loading-text-color: color-mix(
- in srgb,
- hsl(var(--foreground)) 88%,
- hsl(var(--background)) 12%
- );
- --buzz-grainient-color-0: hsl(
- var(--chart-5) /
- var(--buzz-grainient-alpha-strong)
- );
- --buzz-grainient-color-1: hsl(
- var(--chart-3) /
- var(--buzz-grainient-alpha-strong)
- );
- --buzz-grainient-color-2: hsl(
- var(--primary) /
- var(--buzz-grainient-alpha-medium)
- );
- --buzz-grainient-color-3: hsl(
- var(--chart-2) /
- var(--buzz-grainient-alpha-strong)
- );
- background-color: hsl(var(--background));
- color: hsl(var(--foreground));
- isolation: isolate;
- position: relative;
-}
-
-.dark .buzz-setup-loading-shell {
- --buzz-grainient-alpha-strong: 0.68;
- --buzz-grainient-alpha-medium: 0.5;
- --buzz-grainient-alpha-soft: 0.34;
- --buzz-setup-loading-text-color: color-mix(
- in srgb,
- hsl(var(--foreground)) 94%,
- hsl(var(--background)) 6%
- );
-}
-
-.buzz-setup-grainient {
- inset: 0;
- overflow: hidden;
- pointer-events: none;
- position: absolute;
- z-index: 0;
-}
-
-.buzz-setup-grainient__wash,
-.buzz-setup-grainient__veil {
- inset: 0;
- position: absolute;
-}
-
-.buzz-setup-grainient__wash {
- --buzz-grainient-s-start-0: 9%;
- --buzz-grainient-s-end-0: 55%;
- --buzz-grainient-s-start-1: 5%;
- --buzz-grainient-s-end-1: 72%;
- --buzz-grainient-s-start-2: 5%;
- --buzz-grainient-s-end-2: 52%;
- --buzz-grainient-s-start-3: 13%;
- --buzz-grainient-s-end-3: 68%;
- --buzz-grainient-x-0: 85%;
- --buzz-grainient-y-0: 80%;
- --buzz-grainient-x-1: 60%;
- --buzz-grainient-y-1: 24%;
- --buzz-grainient-x-2: 13%;
- --buzz-grainient-y-2: 82%;
- --buzz-grainient-x-3: 24%;
- --buzz-grainient-y-3: 7%;
- animation: buzz-grainient-orbit 10s linear infinite alternate;
- background-color: hsl(var(--background));
- background-image:
- radial-gradient(
- circle at var(--buzz-grainient-x-0) var(--buzz-grainient-y-0),
- var(--buzz-grainient-color-0) var(--buzz-grainient-s-start-0),
- transparent var(--buzz-grainient-s-end-0)
- ),
- radial-gradient(
- circle at var(--buzz-grainient-x-1) var(--buzz-grainient-y-1),
- var(--buzz-grainient-color-1) var(--buzz-grainient-s-start-1),
- transparent var(--buzz-grainient-s-end-1)
- ),
- radial-gradient(
- circle at var(--buzz-grainient-x-2) var(--buzz-grainient-y-2),
- var(--buzz-grainient-color-2) var(--buzz-grainient-s-start-2),
- transparent var(--buzz-grainient-s-end-2)
- ),
- radial-gradient(
- circle at var(--buzz-grainient-x-3) var(--buzz-grainient-y-3),
- var(--buzz-grainient-color-3) var(--buzz-grainient-s-start-3),
- transparent var(--buzz-grainient-s-end-3)
- );
- background-blend-mode: normal, normal, normal, normal;
- contain: paint;
- filter: saturate(1.08);
- transform: translateZ(0);
- will-change: transform, opacity;
-}
-
-.buzz-setup-grainient__veil {
- background:
- radial-gradient(
- ellipse 74% 54% at 50% 52%,
- transparent 0%,
- hsl(var(--background) / 0.04) 72%,
- hsl(var(--background) / 0.16) 100%
- ),
- linear-gradient(
- 180deg,
- hsl(var(--background) / 0.04),
- hsl(var(--background) / 0.12)
- );
-}
-
-.buzz-setup-loading-text {
- animation: buzz-setup-character-rise 700ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
- backface-visibility: hidden;
- color: var(--buzz-setup-loading-text-color);
- display: inline-block;
- opacity: 0;
- text-shadow:
- 0 1px 2px hsl(var(--background) / 0.62),
- 0 14px 34px hsl(var(--background) / 0.5);
- transform: translate3d(0, 32px, 0);
- transform-origin: 50% 55%;
- will-change: transform, opacity;
-}
-
-@keyframes buzz-grainient-orbit {
- 0% {
- --buzz-grainient-x-0: 85%;
- --buzz-grainient-y-0: 80%;
- --buzz-grainient-x-1: 60%;
- --buzz-grainient-y-1: 24%;
- --buzz-grainient-x-2: 13%;
- --buzz-grainient-y-2: 82%;
- --buzz-grainient-x-3: 24%;
- --buzz-grainient-y-3: 7%;
- }
-
- 100% {
- --buzz-grainient-x-0: 31%;
- --buzz-grainient-y-0: 94%;
- --buzz-grainient-x-1: 2%;
- --buzz-grainient-y-1: 25%;
- --buzz-grainient-x-2: 98%;
- --buzz-grainient-y-2: 20%;
- --buzz-grainient-x-3: 95%;
- --buzz-grainient-y-3: 92%;
- }
-}
-
-@keyframes buzz-setup-character-rise {
- from {
- opacity: 0;
- transform: translate3d(0, 32px, 0);
- }
-
- to {
- opacity: 1;
- transform: translate3d(0, 0, 0);
- }
-}
-
-@media (prefers-reduced-motion: reduce) {
- .buzz-setup-grainient__wash {
- animation: none;
- }
-
- .buzz-setup-loading-text {
- animation: none;
- opacity: 1;
- transform: none;
- }
-}
-
.buzz-avatar-hue-scrubber {
background: linear-gradient(
90deg,
diff --git a/desktop/src/shared/ui/buzz-logo/BuzzMark.tsx b/desktop/src/shared/ui/buzz-logo/BuzzMark.tsx
new file mode 100644
index 000000000..9fd4db1dc
--- /dev/null
+++ b/desktop/src/shared/ui/buzz-logo/BuzzMark.tsx
@@ -0,0 +1,57 @@
+import { useId } from "react";
+
+/**
+ * The finished Buzz mark as a plain static SVG — no SMIL, no scripting, no
+ * animation machinery. Geometry matches the final keyframe of the
+ * BuzzLogoAnimation morph (v8 variant), rendered in `currentColor`, so it
+ * paints complete on the very first frame regardless of animation support.
+ */
+export function BuzzMark({ className }: { className?: string }) {
+ const maskId = `buzz-mark-cutouts-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
+
+ return (
+
+ );
+}
diff --git a/desktop/tests/e2e/onboarding.spec.ts b/desktop/tests/e2e/onboarding.spec.ts
index bc136ed81..6b5eb2cb2 100644
--- a/desktop/tests/e2e/onboarding.spec.ts
+++ b/desktop/tests/e2e/onboarding.spec.ts
@@ -1054,7 +1054,7 @@ test("first-run onboarding shows setup loading until Welcome bootstrap completes
await seedActiveIdentity(page, BLANK_TYLER_IDENTITY);
await installMockBridge(
page,
- { createManagedAgentDelayMs: 5_000 },
+ { createManagedAgentDelayMs: 9_000 },
{ skipOnboardingSeed: true },
);
await page.goto("/");
@@ -1067,47 +1067,45 @@ test("first-run onboarding shows setup loading until Welcome bootstrap completes
await expect(page.getByTestId("onboarding-gate")).toHaveCount(0);
await expect(loadingGate).toBeVisible();
await expect(loadingGate).toContainText("Setting up your workspace...");
- await expect(
- loadingGate.getByTestId("setup-grainient-background"),
- ).toBeVisible();
- await expect(
- loadingGate.getByTestId("setup-grainient-background").locator("canvas"),
- ).toHaveCount(0);
- await expect
- .poll(async () =>
- loadingGate.evaluate((element) => {
- const wash = element.querySelector(".buzz-setup-grainient__wash");
- if (!(wash instanceof HTMLElement)) {
- return null;
- }
- const shellStyles = window.getComputedStyle(element);
- const washStyles = window.getComputedStyle(wash);
- const loadingText = element.querySelector(".buzz-setup-loading-text");
- const textStyles =
- loadingText instanceof HTMLElement
- ? window.getComputedStyle(loadingText)
- : null;
- return {
- animationName: washStyles.animationName,
- backgroundMatchesTheme:
- shellStyles.backgroundColor === washStyles.backgroundColor,
- textAvoidsHardcodedWhite: textStyles?.color !== "rgb(255, 255, 255)",
- usesRadialGradients:
- washStyles.backgroundImage.includes("radial-gradient"),
- };
- }),
- )
- .toEqual({
- animationName: "buzz-grainient-orbit",
- backgroundMatchesTheme: true,
- textAvoidsHardcodedWhite: true,
- usesRadialGradients: true,
- });
+ // The boot gate is deliberately static: a plain Buzz mark in the brand
+ // yellow (#D7D72E) over solid black. The mark must paint complete on the
+ // FIRST frame — a blank gate reads as "nothing is loading" — so nothing
+ // about it may depend on SMIL/scripted animation, and the background must
+ // be a flat color rather than the animated gradient wash.
+ const mark = loadingGate.locator(".buzz-mark");
+ await expect(mark).toBeVisible();
+ const gateTreatment = await loadingGate.evaluate((element) => {
+ const shellStyles = window.getComputedStyle(element);
+ const markSvg = element.querySelector(".buzz-mark");
+ const markStyles =
+ markSvg instanceof SVGElement ? window.getComputedStyle(markSvg) : null;
+ return {
+ animateElementCount: element.querySelectorAll("animate").length,
+ backgroundColor: shellStyles.backgroundColor,
+ backgroundImage: shellStyles.backgroundImage,
+ // The document itself must also be black (inline