From 2eb9ca2d8f95d9fa374c8de1b443a5a7f7639f55 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Mon, 16 Mar 2026 16:37:36 -0700 Subject: [PATCH] fix(rsplat): use queue API for Hunyuan3D + fix controls z-index Also fix canvas.html null reference crash when share-badge is stripped by extractCanvasContent() header removal. Co-Authored-By: Claude Opus 4.6 --- modules/rsplat/components/folk-splat-viewer.ts | 14 +++++++++++--- website/canvas.html | 8 -------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/rsplat/components/folk-splat-viewer.ts b/modules/rsplat/components/folk-splat-viewer.ts index 60d9499..c6b74c5 100644 --- a/modules/rsplat/components/folk-splat-viewer.ts +++ b/modules/rsplat/components/folk-splat-viewer.ts @@ -571,10 +571,14 @@ export class FolkSplatViewer extends HTMLElement { headers: { "Content-Type": "application/json" }, body: JSON.stringify({ image_url: imageUrl, title }), }); - clearInterval(ticker); - document.removeEventListener("visibilitychange", onVisChange); + + const stopTicker = () => { + clearInterval(ticker); + document.removeEventListener("visibilitychange", onVisChange); + }; if (res.status === 524 || res.status === 504) { + stopTicker(); status.textContent = "Generation timed out — try a simpler image."; progress.style.display = "none"; actions.style.display = "flex"; @@ -583,6 +587,7 @@ export class FolkSplatViewer extends HTMLElement { } if (res.status === 503) { + stopTicker(); status.textContent = "AI generation not available — FAL_KEY not configured"; progress.style.display = "none"; actions.style.display = "flex"; @@ -591,6 +596,7 @@ export class FolkSplatViewer extends HTMLElement { } if (!res.ok) { + stopTicker(); const err = await res.json().catch(() => ({ error: "Generation failed" })); status.textContent = (err as any).error || "Generation failed"; progress.style.display = "none"; @@ -600,7 +606,7 @@ export class FolkSplatViewer extends HTMLElement { } const { job_id } = await res.json() as { job_id: string }; - status.textContent = "Generating 3D model — you'll get an email when it's ready..."; + // Ticker keeps running — progress bar continues advancing during polling // Poll for completion const pollInterval = setInterval(async () => { @@ -610,6 +616,7 @@ export class FolkSplatViewer extends HTMLElement { const job = await pollRes.json() as any; if (job.status === "complete") { + stopTicker(); clearInterval(pollInterval); progress.style.display = "none"; @@ -683,6 +690,7 @@ export class FolkSplatViewer extends HTMLElement { }); } else if (job.status === "failed") { + stopTicker(); clearInterval(pollInterval); progress.style.display = "none"; status.textContent = job.error || "Generation failed"; diff --git a/website/canvas.html b/website/canvas.html index 6b80e15..dabb579 100644 --- a/website/canvas.html +++ b/website/canvas.html @@ -2931,24 +2931,18 @@ } layers = sync.getLayers?.() || []; tabBar.setLayers(layers); - const activeId = sync.doc?.activeLayerId; - if (activeId) tabBar.setAttribute('active', activeId); if (sync.getFlows) tabBar.setFlows(sync.getFlows()); } else { // First connection: push all localStorage tabs into Automerge for (const l of layers) { sync.addLayer?.(l); } - sync.setActiveLayer?.('layer-' + currentModuleId); } // Keep localStorage in sync saveTabs(); // Sync layer changes back to Automerge - tabBar.addEventListener('layer-switch', (e) => { - sync.setActiveLayer?.(e.detail.layerId); - }); tabBar.addEventListener('layer-add', (e) => { const { moduleId } = e.detail; const newLayer = makeLayer(moduleId, sync.getLayers?.().length || 0); @@ -2975,8 +2969,6 @@ layers = sync.getLayers?.() || []; tabBar.setLayers(layers); if (sync.getFlows) tabBar.setFlows(sync.getFlows()); - const activeId = sync.doc?.activeLayerId; - if (activeId) tabBar.setAttribute('active', activeId); const viewMode = sync.doc?.layerViewMode; if (viewMode) tabBar.setAttribute('view-mode', viewMode); saveTabs(); // keep localStorage in sync