From 96be4ec3511b894a14f2f7246d57ab4dd58c9c58 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sat, 23 May 2026 01:07:26 -0400 Subject: [PATCH] =?UTF-8?q?Add=20an=20"Initializing=20Renderer=E2=80=A6"?= =?UTF-8?q?=20overlay=20when=20Vello=20shader=20compilation=20is=20slow=20?= =?UTF-8?q?on=20web?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/panels/Document.svelte | 40 ++++++++++++++++++- frontend/src/utility-functions/viewports.ts | 10 +++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/panels/Document.svelte b/frontend/src/components/panels/Document.svelte index a80bb47f6d..5044490212 100644 --- a/frontend/src/components/panels/Document.svelte +++ b/frontend/src/components/panels/Document.svelte @@ -7,6 +7,7 @@ import Graph from "/src/components/views/Graph.svelte"; import RulerInput from "/src/components/widgets/inputs/RulerInput.svelte"; import ScrollbarInput from "/src/components/widgets/inputs/ScrollbarInput.svelte"; + import TextLabel from "/src/components/widgets/labels/TextLabel.svelte"; import WidgetLayout from "/src/components/widgets/WidgetLayout.svelte"; import type { AppWindowStore } from "/src/stores/app-window"; import type { DocumentStore } from "/src/stores/document"; @@ -16,7 +17,7 @@ import { pasteFile } from "/src/utility-functions/files"; import { textInputCleanup } from "/src/utility-functions/keyboard-entry"; import { rasterizeSVGCanvas } from "/src/utility-functions/rasterization"; - import { setupViewportResizeObserver } from "/src/utility-functions/viewports"; + import { setupViewportResizeObserver, hasFirstArtworkBeenReceived, markFirstArtworkReceived } from "/src/utility-functions/viewports"; import type { EditorWrapper, MenuDirection, MouseCursorIcon, SRGBA8 } from "/wrapper/pkg/graphite_wasm_wrapper"; let rulerHorizontal: RulerInput | undefined; @@ -53,6 +54,10 @@ // Rendered SVG viewport data let artworkSvg = ""; + // Web-only "Initializing Renderer…" overlay shown until the first Vello-rendered artwork arrives + const isWeb = import.meta.env.MODE !== "native"; + let firstArtworkReceived = hasFirstArtworkBeenReceived(); + // Rasterized SVG viewport data, or none if it's not up-to-date let rasterizedCanvas: HTMLCanvasElement | undefined = undefined; let rasterizedContext: CanvasRenderingContext2D | undefined = undefined; @@ -470,6 +475,11 @@ subscriptions.subscribeFrontendMessage("UpdateDocumentArtwork", async (data) => { await tick(); + if (!firstArtworkReceived) { + firstArtworkReceived = true; + markFirstArtworkReceived(); + } + updateDocumentArtwork(data.svg); }); subscriptions.subscribeFrontendMessage("UpdateEyedropperSamplingState", async (data) => { @@ -708,6 +718,9 @@ > {/if} + {#if isWeb} + Initializing Renderer… + {/if}
@@ -944,6 +957,31 @@ unicode-bidi: plaintext; } + .shader-compiling-overlay { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; + opacity: 0; + transition: opacity 0.5s ease; + + &.show { + opacity: 1; + animation: shader-compiling-overlay-fade-in 0.5s ease 0.5s both; + } + + @keyframes shader-compiling-overlay-fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + } + .text-input div { cursor: text; background: none; diff --git a/frontend/src/utility-functions/viewports.ts b/frontend/src/utility-functions/viewports.ts index 3208e68e9f..b1916ce47e 100644 --- a/frontend/src/utility-functions/viewports.ts +++ b/frontend/src/utility-functions/viewports.ts @@ -1,5 +1,15 @@ import type { EditorWrapper } from "/wrapper/pkg/graphite_wasm_wrapper"; +// Tracks whether any document has produced its first frame of rendered artwork yet during this app session. +// Used to show the one-time "Initializing Renderer…" overlay only on the very first document open. +let firstArtworkEverReceived = false; +export function hasFirstArtworkBeenReceived(): boolean { + return firstArtworkEverReceived; +} +export function markFirstArtworkReceived(): void { + firstArtworkEverReceived = true; +} + export function setupViewportResizeObserver(editor: EditorWrapper): () => void { const viewports = Array.from(window.document.querySelectorAll("[data-viewport-container]")); if (viewports.length <= 0) return () => {};