How to View and Embed Gaussian Splatting on the Web
Updated Mar 2026
Gaussian Splatting has gone from an academic curiosity to a practical tool in under two years — and the browser is now a first-class deployment target. A typical outdoor scene captured with Polycam or Scaniverse clocks in between 80 MB and 400 MB as a raw PLY, but modern web viewers load and render these at 60 fps on a mid-range laptop. The trick is understanding what each viewer actually does with your data. There are four main approaches to 3DGS on the web right now: 1. **Privacy-first local viewers** like polyvia3d process the entire file inside the browser with WebGL/WebGPU — nothing ever leaves your machine. A 120 MB PLY loads in roughly 3–5 seconds on a 2022 MacBook Pro. 2. **Embeddable JS libraries** like gsplat.js (~180 KB gzipped) and antimatter15/splat give you full control over the render loop and let you integrate 3DGS into any Three.js or Babylon.js scene. 3. **Hosted platforms** like PlayCanvas SuperSplat stream splats from their CDN and offer no-code embedding with a single `<iframe>`. Fast to deploy, but your file lives on their servers. 4. **WebGPU-native renderers** are emerging fast — Mip-Splatting, 2DGS, and compressed formats like SPZ all have experimental web implementations. Choosing the wrong approach burns you in obvious ways: a 350 MB PLY embedded via iframe on a shared CDN will time out for mobile users. Conversely, a JS library drop-in is overkill when you just want visitors to view a single scan. This guide walks through each option with realistic expectations, then shows you exactly how to implement the two most common patterns: iframe embed and gsplat.js integration. Mobile is the hidden constraint. WebGL Gaussian Splatting works on iOS Safari 16+ and Chrome Android 115+, but frame rates drop to 20–30 fps on older devices at full splat counts. The section on performance optimisation covers the practical knobs: splat count culling, poster images for perceived load, and the SPZ format (10× smaller than PLY) for bandwidth-constrained deployments.
Tools used in this guide
Step-by-Step Guide
- 1
Understand Your Viewer Options
Before picking a viewer, measure your file. Open your PLY or SPLAT file in polyvia3d's PLY Gaussian Viewer at /splat-viewer/ply to get the splat count and estimated render weight — a scene with more than 3 million splats will struggle on mobile regardless of viewer. The four main options by use case: **polyvia3d** for privacy-sensitive or offline scenarios (zero upload, runs in your browser tab); **gsplat.js** when you need to integrate 3DGS into an existing Three.js application (npm install gsplat, ~180 KB bundle overhead); **antimatter15/splat** for minimal-dependency implementations (single JS file, no build step); **SuperSplat by PlayCanvas** when you want a hosted no-code solution and don't mind your file living on their CDN. If you're undecided, start with polyvia3d for validation — it supports PLY, SPZ, SPLAT, and KSplat formats natively.
- 2
Optimise Your Splat File Before Embedding
Raw PLY exports from training tools (3D Gaussian Splatting original, nerfstudio, gsplat library) are uncompressed and large. A garden scene trained for 30K iterations typically produces a 150–300 MB PLY. Before embedding, convert to a compressed format. SPZ (Niantic/Scaniverse format) achieves 8–12× compression with minimal visible quality loss — a 200 MB PLY commonly compresses to 18–22 MB SPZ. Use polyvia3d's PLY to SPZ converter at /splat-convert/ply-to-spz directly in your browser. SPLAT format (antimatter15) offers 4–6× compression with faster decode but wider compatibility. KSplat adds level-of-detail on top, which helps for scenes above 2 million splats. Rule of thumb: keep your embedded file under 30 MB for a sub-3-second load on a typical broadband connection (25 Mbps).
- 3
Embed via iframe (Hosted Platform Approach)
The fastest path to embedding is hosting your splat on a platform that provides an iframe snippet. Upload your file to SuperSplat (playcanvas.com/supersplat) or Luma AI, then copy their embed code. A typical SuperSplat iframe looks like: `<iframe src="https://supersplat.playcanvas.com/viewer/?url=YOUR_FILE_URL" width="100%" height="500" frameborder="0" allow="fullscreen"></iframe>`. Key attributes to set: `allow="fullscreen"` for immersive viewing; a fixed `height` of 400–600 px for desktop layouts; `loading="lazy"` to defer loading below the fold. Downsides: you depend on the host's uptime, you can't customise renderer behaviour, and file size is constrained by the platform's upload limits (SuperSplat free tier: 200 MB). Always include a static poster image as a fallback for users whose browsers block iframes.
- 4
Integrate gsplat.js Into Your Own Site
For full control, use gsplat.js. Install via npm: `npm install gsplat`. The minimal setup loads a splat and renders it into a canvas element in about 15 lines of code. Import `Scene`, `Renderer`, and `Camera` from the package; create a renderer targeting your `<canvas id="canvas">`; call `scene.loadFromURL("/your-scene.spz")` (gsplat.js supports PLY, SPLAT, and SPZ natively); then start the render loop with `renderer.render(scene, camera)` in a `requestAnimationFrame` callback. Performance tip: set `renderer.setSize(window.innerWidth, window.innerHeight)` once on load and listen for resize events rather than reading it on every frame — this alone saves ~2 ms per frame on complex scenes.
- 5
Add a Poster Image for Perceived Performance
Regardless of viewer, always render a static poster image — a WebP screenshot of your splat at 1200×630 px. This serves three purposes: it gives users something to look at during the 2–5 second load; it acts as the Open Graph image for link previews; and it gives search engines image content to index (3DGS files themselves are not crawlable). Generate the poster by opening your splat in polyvia3d's viewer, framing the best angle, and using the browser's screenshot tool (F12 → device toolbar → screenshot, or a browser extension). Serve the poster as a `<img>` behind the canvas element with `z-index: -1` so it disappears the moment the 3D scene renders. This pattern cuts perceived load time by 40–60% in user testing.
- 6
Optimise for Mobile
Mobile is where 3DGS embeds fail most often. iPhones from 2020 onwards handle 1–2 million splats at 30 fps; Android midrange (Snapdragon 7xx) is similar. Above that, frame rates drop to single digits. Strategies: (1) Reduce splat count — re-export from your training tool at a lower iteration count (15K instead of 30K) for a mobile-targeted version; a 15K iteration garden scene typically has 800K splats vs 2.2M at 30K. (2) Use SPZ — smaller file means faster initial load, which matters more on mobile where the user may not wait. (3) Detect GPU tier at runtime using the WebGL renderer info (`gl.getParameter(gl.RENDERER)`) and load a lower-count variant for mobile. (4) Set a pixel ratio cap: `renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.5))` — this alone recovers 25–30% frame time on high-DPI mobile screens.
- 7
Test Across Browsers and Validate Load Times
Test your embed in Chrome 120+, Safari 16.4+, and Firefox 121+ before going live. Safari historically had the most issues with large TypedArray allocations (used internally by splat renderers) — this was largely fixed in Safari 16.4. Use Chrome DevTools Network tab with throttling set to "Fast 3G" to simulate the real-world load experience for mobile users: a 25 MB SPZ file should appear loaded within 8 seconds on Fast 3G, versus under 2 seconds on broadband. If your file takes longer, either reduce it further or implement progressive loading — some viewers (including gsplat.js) support streaming PLY that renders splats as they download. Check the browser console for WebGL context lost events, which indicate GPU memory pressure and suggest your splat count is too high for the target device.