From 7da90088c419f66e0e05406e6d8eb484882a78bf Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Mon, 16 Mar 2026 23:15:24 +0000 Subject: [PATCH] fix(rsplat): fix GLB viewer not rendering on mobile Defer initThreeViewer to next animation frame so the DOM has laid out before reading container dimensions. Fall back to viewport size instead of hardcoded 800x600 when container reports zero dimensions. Add proper MIME types for GLB/GLTF file serving. Co-Authored-By: Claude Opus 4.6 (1M context) --- modules/rsplat/components/folk-splat-viewer.ts | 10 +++++++--- server/index.ts | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/rsplat/components/folk-splat-viewer.ts b/modules/rsplat/components/folk-splat-viewer.ts index 22ce55b..0ac6121 100644 --- a/modules/rsplat/components/folk-splat-viewer.ts +++ b/modules/rsplat/components/folk-splat-viewer.ts @@ -791,7 +791,7 @@ export class FolkSplatViewer extends HTMLElement { // Download handler this.querySelector("#splat-download-btn")?.addEventListener("click", () => this.downloadModel()); - this.initThreeViewer(); + requestAnimationFrame(() => this.initThreeViewer()); } private async downloadModel() { @@ -997,8 +997,12 @@ export class FolkSplatViewer extends HTMLElement { const { OrbitControls } = await import("three/addons/controls/OrbitControls.js"); const { GLTFLoader } = await import("three/addons/loaders/GLTFLoader.js"); - const w = container.clientWidth || 800; - const h = container.clientHeight || 600; + // Wait for layout if container has no dimensions yet + if (!container.clientWidth || !container.clientHeight) { + await new Promise((r) => requestAnimationFrame(r)); + } + const w = container.clientWidth || window.innerWidth; + const h = container.clientHeight || (window.innerHeight - 56); const scene = new THREE.Scene(); scene.background = new THREE.Color(0x0f0f14); diff --git a/server/index.ts b/server/index.ts index ca50c29..1c37130 100644 --- a/server/index.ts +++ b/server/index.ts @@ -196,7 +196,7 @@ app.get("/data/files/generated/:filename", async (c) => { const file = Bun.file(filePath); if (!(await file.exists())) return c.notFound(); const ext = filename.split(".").pop() || ""; - const mimeMap: Record = { png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", webp: "image/webp" }; + const mimeMap: Record = { png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", webp: "image/webp", glb: "model/gltf-binary", gltf: "model/gltf+json" }; return new Response(file, { headers: { "Content-Type": mimeMap[ext] || "application/octet-stream", "Cache-Control": "public, max-age=86400" } }); });