@heliguy-xyz/splat-viewer
Version:
A standalone 3D Gaussian Splat viewer web component with multi-model support, transform system, fly camera, and scene configuration
344 lines (267 loc) ⢠10.2 kB
Markdown
# Heliguy Web Viewer
A self-contained 3D Gaussian Splat viewer web component built with PlayCanvas for high-performance
rendering of point cloud data. Framework-agnostic and embeddable in any web application with zero
external dependencies.
## Features
- šÆ **Gaussian Splat Rendering**: Native support for `.splat` files using PlayCanvas
- š **PLY Support**: Traditional point cloud rendering for `.ply` and `.ply.compressed` formats
- š¦ **SOG Support**: Native support for `.sog` (Spatially Ordered Gaussians) files
- š® **Interactive Controls**: Smooth camera navigation and manipulation
- š§ **Navigation Cube**: Interactive 3D cube for quick camera orientation control
- š **Performance Monitoring**: Real-time rendering statistics
- ā” **High Performance**: WebGL2-powered rendering with PlayCanvas engine
- š± **Responsive Design**: Full-screen immersive viewing experience
- š§ **Self-Contained**: Single file with bundled PlayCanvas engine (2MB)
- šØ **Built-in Loading**: Professional loading spinner with orange/black theme
- š **Zero Dependencies**: No external scripts required
### Enhanced Features (v1.0.0)
- š **Multi-Model Support**: Load and manage multiple models in the same scene
- š **Transform System**: Programmatically position, rotate, and scale models
- š„ **Fly Camera Mode**: First-person WASD + mouse-look navigation with configurable controls
- šØ **Scene Configuration**: Adjust FOV and background color with smooth animations
- š” **Comprehensive Events**: React to model lifecycle, transforms, camera changes, and more
- š **TypeScript Support**: Full type definitions for all APIs
## Quick Start
### Installation
#### Via npm (Recommended)
```bash
npm install @heliguy/web-viewer
```
#### Via CDN
```html
<!-- UMD Bundle -->
<script src="https://unpkg.com/@heliguy/web-viewer@1.0.0/dist/web-component/splat-viewer.min.js"></script>
<!-- ESM Bundle -->
<script type="module">
import '@heliguy/web-viewer/esm'
</script>
```
### Prerequisites
- Modern browser with WebGL2 support
- Node.js ā„18.0.0 (for development only)
### Usage
#### Vanilla HTML
```html
<!DOCTYPE html>
<html>
<head>
<title>3D Splat Viewer</title>
</head>
<body>
<splat-viewer
id="viewer"
width="100%"
height="600px"
auto-focus
enable-navigation-cube
></splat-viewer>
<!-- Import from npm package -->
<script src="node_modules/@heliguy/web-viewer/dist/web-component/splat-viewer.min.js"></script>
<script>
const viewer = document.getElementById('viewer')
viewer.addEventListener('ready', () => {
viewer.load('path/to/model.splat')
})
</script>
</body>
</html>
```
#### Embed via iframe
Use the provided `viewer.html` page that reads query parameters and configures the web component.
Host `viewer.html` alongside `dist/web-component/splat-viewer.min.js`.
Supported query params:
- `src` (required): URL to your model (encode it!)
- `width` (optional): CSS width (e.g. `100%`, `800px`)
- `height` (optional): CSS height (e.g. `100vh`, `600px`)
- `autoFocus` (optional): `true` | `false` (default: `true`)
- `stats` (optional): `true` | `false`
Example:
```html
<iframe
src="https://your-domain.com/viewer.html?src=https%3A%2F%2Fcdn.yourdomain.com%2Fmodels%2FRyhope.ply&width=100%25&height=100vh&autoFocus=true"
width="100%"
height="600"
style="border:0; background:#000"
allowfullscreen
></iframe>
```
Notes:
- Ensure CORS allows the viewer origin to fetch the model (`Access-Control-Allow-Origin`).
- Prefer hosting `viewer.html`, the bundle, and models on the same domain to avoid CORS.
- URL-encode the `src` value.
#### React / Next.js
```tsx
import { useEffect, useRef } from 'react'
import '@heliguy/web-viewer'
function App() {
const viewerRef = useRef<any>(null)
useEffect(() => {
const viewer = viewerRef.current
if (!viewer) return
const handleReady = () => {
viewer.load('/models/scene.splat')
}
viewer.addEventListener('ready', handleReady)
return () => viewer.removeEventListener('ready', handleReady)
}, [])
return (
<splat-viewer
ref={viewerRef}
width="100%"
height="600px"
auto-focus
/>
)
}
```
**TypeScript:** Add to your `global.d.ts`:
```typescript
declare namespace JSX {
interface IntrinsicElements {
'splat-viewer': React.DetailedHTMLProps<
React.HTMLAttributes<HTMLElement> & {
ref?: React.Ref<any>
src?: string
width?: string
height?: string
'auto-focus'?: boolean
'enable-stats'?: boolean
},
HTMLElement
>
}
}
```
#### Vue 3
```vue
<template>
<splat-viewer
ref="viewerRef"
width="100%"
height="600px"
auto-focus
/>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import '@heliguy/web-viewer'
const viewerRef = ref(null)
onMounted(() => {
const viewer = viewerRef.value
const handleReady = () => {
viewer.load('/models/scene.splat')
}
viewer.addEventListener('ready', handleReady)
})
</script>
```
## Commands
| Command | Description |
| ----------------------------- | ---------------------------------- |
| `npm run web-component:serve` | Start development server |
| `npm run web-component:build` | Build self-contained web component |
| `npm run web-component:clean` | Clean build artifacts |
| `npm run lint` | Check code quality with ESLint |
| `npm run lint:fix` | Fix linting issues automatically |
| `npm run format` | Format code with Prettier |
| `npm run format:check` | Check code formatting |
## Web Component API
### Attributes
#### Basic Configuration
- `src` - Model file path or URL
- `width` - Canvas width (default: "100%")
- `height` - Canvas height (default: "400px")
- `auto-focus` - Auto-focus on load (default: true)
- `enable-stats` - Show performance stats (default: false)
- `max-splats` - Maximum splat count (default: 2000000)
#### Camera Controls
- `orbit-sensitivity` - Mouse orbit sensitivity (default: 0.3)
- `pan-sensitivity` - Mouse pan sensitivity (default: 0.5)
- `zoom-sensitivity` - Mouse zoom sensitivity (default: 0.1)
- `min-distance` - Minimum camera distance (default: 1)
- `max-distance` - Maximum camera distance (default: 100)
#### Navigation Cube
- `enable-navigation-cube` - Show interactive navigation cube (default: false)
- `navigation-cube-size` - Cube size in pixels (default: 120)
- `navigation-cube-transition` - Camera transition duration in ms (default: 800)
### Events
#### Core Events
- `ready` - Component initialized
- `loading-start` - Model loading started
- `loading-progress` - Model loading progress update
- `loaded` - Model loaded successfully
- `error` - Loading error occurred
- `stats-update` - Performance statistics update
- `camera-change` - Camera position/target changed
- `interaction-start` / `interaction-end` - User interaction with orbit controls
#### Multi-Model Events (v1.0.0)
- `model-added` - Model added to scene
- `model-removed` - Model removed from scene
- `scene-cleared` - All models cleared
#### Transform Events (v1.0.0)
- `model-transform-changed` - Model transform updated
#### Camera Events (v1.0.0)
- `camera-mode-changed` - Camera mode switched (orbit/fly)
- `fly-camera-move` - Fly camera position changed
- `fly-camera-look` - Fly camera rotation changed
#### Scene Config Events (v1.0.0)
- `camera-fov-changed` - Camera FOV changed
- `background-color-changed` - Background color changed
## Project Structure
```
src/
āāā web-component/ # Main web component implementation
ā āāā SplatViewerElement.ts # Web component class
ā āāā SplatViewerCore.ts # Core rendering engine
ā āāā NavigationCubeController.ts # Navigation cube controller
ā āāā OrbitCameraScript.ts # Camera controls
ā āāā navigation-cube/ # Navigation cube modules
ā ā āāā CubeRenderer.ts # 3D cube visual rendering
ā ā āāā ControlPointManager.ts # Control point UI elements
ā ā āāā CameraTransitionController.ts # Camera animations
ā āāā types/ # TypeScript definitions
ā āāā loader/ # File loading system (.ply, .sog, .splat)
ā āāā utils/ # Utility functions
āāā build/ # Build configuration
āāā dist/web-component/ # Built self-contained web component
ā āāā splat-viewer.min.js # Single 2MB file with PlayCanvas
āāā test-web-component.html # Basic test page
āāā test-navigation-cube.html # Navigation cube test page
assets/ # 3D model assets for testing
docs/ # Documentation
```
## Supported File Formats
- **.sog** - Spatially Ordered Gaussians (PlayCanvas native support)
- **.splat** - Gaussian Splat files (PlayCanvas native support)
- **.ply** - Point cloud files (standard format)
- **.ply.compressed** - Compressed PLY files (gzip/deflate)
## Self-Contained Bundle
The web component is distributed as a single 2MB file (`splat-viewer.min.js`) that includes:
- Complete PlayCanvas engine (v2.11.8)
- Web component implementation
- File format loaders
- Performance monitoring
- Interactive controls
**Benefits:**
- Zero external dependencies
- Version consistency guaranteed
- Easy embedding in any web application
- Offline functionality
## Development
```bash
# Start development server
npm run web-component:serve
# Build for production
npm run web-component:build
# Clean build artifacts
npm run web-component:clean
```
## Deployment
### Netlify
- Publish directory: `dist`
- Build command: `npm run build`
- Node version: 18 (configured in `netlify.toml`)
The build emits `dist/index.html` from `viewer.html` using a small zero-dependency Node script
(`build/copy-viewer-to-index.mjs`). Rollup uses an ESM config at `build/rollup.config.mjs`.
## License
MIT License - see LICENSE file for details.