diff --git a/modules/splat/components/folk-splat-viewer.ts b/modules/splat/components/folk-splat-viewer.ts index b118d57..2425f40 100644 --- a/modules/splat/components/folk-splat-viewer.ts +++ b/modules/splat/components/folk-splat-viewer.ts @@ -263,12 +263,11 @@ export class FolkSplatViewer extends HTMLElement { try { // Dynamic import from CDN (via importmap) - const THREE = await import("three"); const GaussianSplats3D = await import("@mkkellogg/gaussian-splats-3d"); const viewer = new GaussianSplats3D.Viewer({ - cameraUp: [0, -1, 0], - initialCameraPosition: [1, 0.5, 1], + cameraUp: [0, 1, 0], + initialCameraPosition: [5, 3, 5], initialCameraLookAt: [0, 0, 0], rootElement: container, sharedMemoryForWorkers: false, @@ -276,21 +275,28 @@ export class FolkSplatViewer extends HTMLElement { this._viewer = viewer; - await viewer.addSplatScene(this._splatUrl, { + viewer.addSplatScene(this._splatUrl, { showLoadingUI: false, progressiveLoad: true, + }) + .then(() => { + viewer.start(); + if (loading) loading.classList.add("hidden"); + }) + .catch((e: Error) => { + console.error("[rSplat] Scene load error:", e); + if (loading) { + const text = loading.querySelector(".splat-loading__text"); + if (text) text.textContent = `Error: ${e.message}`; + const spinner = loading.querySelector(".splat-loading__spinner") as HTMLElement; + if (spinner) spinner.style.display = "none"; + } }); - - viewer.start(); - - if (loading) { - loading.classList.add("hidden"); - } } catch (e) { console.error("[rSplat] Viewer init error:", e); if (loading) { const text = loading.querySelector(".splat-loading__text"); - if (text) text.textContent = `Error loading splat: ${(e as Error).message}`; + if (text) text.textContent = `Error loading viewer: ${(e as Error).message}`; const spinner = loading.querySelector(".splat-loading__spinner") as HTMLElement; if (spinner) spinner.style.display = "none"; } diff --git a/modules/splat/mod.ts b/modules/splat/mod.ts index b4f26e1..401667f 100644 --- a/modules/splat/mod.ts +++ b/modules/splat/mod.ts @@ -143,7 +143,8 @@ routes.get("/api/splats/:id", async (c) => { }); // ── API: Serve splat file ── -routes.get("/api/splats/:id/file", async (c) => { +// Matches both /api/splats/:id/file and /api/splats/:id/:filename (e.g. rainbow-sphere.splat) +routes.get("/api/splats/:id/:filename", async (c) => { const id = c.req.param("id"); const rows = await sql.unsafe( @@ -351,7 +352,7 @@ routes.get("/view/:id", async (c) => { [splat.id] ); - const fileUrl = `/${spaceSlug}/splat/api/splats/${splat.slug}/file`; + const fileUrl = `/${spaceSlug}/splat/api/splats/${splat.slug}/${splat.slug}.${splat.file_format}`; const html = renderShell({ title: `${splat.title} | rSplat`,