storysplat-viewer 2.7.3 → 2.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +215 -8
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/storysplat-viewer.bundled.umd.js +1 -1
- package/dist/storysplat-viewer.bundled.umd.js.map +1 -1
- package/dist/storysplat-viewer.umd.js +1 -1
- package/dist/storysplat-viewer.umd.js.map +1 -1
- package/dist/types/dynamic-viewer/CameraControls.d.ts +15 -0
- package/dist/types/dynamic-viewer/CharacterController.d.ts +26 -1
- package/dist/types/dynamic-viewer/CustomScriptSystem.d.ts +3 -3
- package/dist/types/dynamic-viewer/FrameSequencePlayer.d.ts +2 -1
- package/dist/types/dynamic-viewer/HtmlMeshHelper.d.ts +3 -1
- package/dist/types/dynamic-viewer/createViewer.d.ts +0 -6
- package/dist/types/dynamic-viewer/viewerUI.d.ts +26 -16
- package/dist/types/index.d.ts +2 -1
- package/dist/types/transformers/sceneToConfig.d.ts +18 -11
- package/dist/types/types/index.d.ts +128 -16
- package/docs/USAGE_GUIDE.md +177 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ A powerful npm package for embedding and interacting with 3D Gaussian Splatting
|
|
|
12
12
|
- [API Reference](#api-reference)
|
|
13
13
|
- [Controlling the Viewer](#controlling-the-viewer)
|
|
14
14
|
- [Configuration Options](#configuration-options)
|
|
15
|
+
- [Internationalization (i18n)](#internationalization-i18n)
|
|
15
16
|
- [Events](#events)
|
|
16
17
|
- [React Integration](#react-integration)
|
|
17
18
|
- [Analytics & Tracking](#analytics--tracking)
|
|
@@ -99,6 +100,27 @@ const viewer = createViewer(
|
|
|
99
100
|
|
|
100
101
|
> **Note:** When using `createViewer` with self-hosted scenes, views and bandwidth are not tracked. Use `createViewerFromSceneId` for StorySplat-hosted scenes to get analytics.
|
|
101
102
|
|
|
103
|
+
### Scene Data Format
|
|
104
|
+
|
|
105
|
+
When using `createViewer()` with self-hosted JSON, the scene data should match the format exported by the StorySplat editor. Key fields:
|
|
106
|
+
|
|
107
|
+
| Field | Type | Description |
|
|
108
|
+
|-------|------|-------------|
|
|
109
|
+
| `loadedModelUrl` | `string` | URL to the .splat, .ply, or .ksplat file |
|
|
110
|
+
| `waypoints` | `array` | Camera path waypoints |
|
|
111
|
+
| `hotspots` | `array` | Interactive hotspot markers |
|
|
112
|
+
| `portals` | `array` | Scene-to-scene navigation portals |
|
|
113
|
+
| `activeSkyboxUrl` | `string` | URL to the skybox HDR/image file |
|
|
114
|
+
| `skyboxRotation` | `number` | Skybox rotation offset |
|
|
115
|
+
| `lights` | `array` | Scene lighting configuration |
|
|
116
|
+
| `particleSystems` | `array` | Particle effect systems |
|
|
117
|
+
| `customMeshes` | `array` | Imported 3D models |
|
|
118
|
+
| `uiColor` | `string` | Accent color for UI controls |
|
|
119
|
+
| `uiOptions` | `object` | UI visibility toggles and button labels |
|
|
120
|
+
| `defaultCameraMode` | `string` | Initial camera mode: `'tour'`, `'explore'`, or `'walk'` |
|
|
121
|
+
|
|
122
|
+
The viewer's transform layer normalizes all field variations automatically, so JSON exported from any version of the editor will work.
|
|
123
|
+
|
|
102
124
|
## API Reference
|
|
103
125
|
|
|
104
126
|
### createViewerFromSceneId
|
|
@@ -163,8 +185,10 @@ async function fetchSceneMeta(
|
|
|
163
185
|
description: string;
|
|
164
186
|
thumbnailUrl: string;
|
|
165
187
|
userName: string;
|
|
188
|
+
userSlug: string;
|
|
166
189
|
views: number;
|
|
167
190
|
tags: string[];
|
|
191
|
+
category?: string;
|
|
168
192
|
createdAt: string | null;
|
|
169
193
|
}>
|
|
170
194
|
```
|
|
@@ -187,21 +211,49 @@ interface ViewerInstance {
|
|
|
187
211
|
getWaypointCount: () => number;
|
|
188
212
|
|
|
189
213
|
// Camera
|
|
214
|
+
setCameraMode: (mode: 'tour' | 'explore') => void;
|
|
215
|
+
getCameraMode: () => string;
|
|
216
|
+
setExploreMode: (mode: 'orbit' | 'fly') => void;
|
|
190
217
|
setPosition: (x: number, y: number, z: number) => void;
|
|
191
218
|
setRotation: (x: number, y: number, z: number) => void;
|
|
192
219
|
getPosition: () => { x: number; y: number; z: number };
|
|
193
220
|
getRotation: () => { x: number; y: number; z: number };
|
|
194
221
|
|
|
195
|
-
// Playback
|
|
222
|
+
// Playback / Progress
|
|
196
223
|
play: () => void;
|
|
197
224
|
pause: () => void;
|
|
198
225
|
stop: () => void;
|
|
199
226
|
isPlaying: () => boolean;
|
|
227
|
+
setProgress: (progress: number) => void;
|
|
228
|
+
getProgress: () => number;
|
|
229
|
+
|
|
230
|
+
// Splat management
|
|
231
|
+
goToSplat: (url: string) => Promise<void>;
|
|
232
|
+
goToOriginalSplat: () => void;
|
|
233
|
+
getCurrentSplatUrl: () => string;
|
|
234
|
+
isShowingOriginalSplat: () => boolean;
|
|
235
|
+
getAdditionalSplats: () => Array<{ url: string; name?: string; waypointIndex: number; percentage: number }>;
|
|
236
|
+
|
|
237
|
+
// Audio
|
|
238
|
+
muteAll: () => void;
|
|
239
|
+
unmuteAll: () => void;
|
|
240
|
+
isMuted: () => boolean;
|
|
241
|
+
|
|
242
|
+
// Hotspots
|
|
243
|
+
getHotspots: () => Array<{ id: string; title?: string; type: string; position: { x: number; y: number; z: number } }>;
|
|
244
|
+
triggerHotspot: (id: string) => void;
|
|
245
|
+
closeHotspot: () => void;
|
|
246
|
+
|
|
247
|
+
// Portals
|
|
248
|
+
navigateToScene: (sceneId: string) => Promise<void>;
|
|
200
249
|
|
|
201
250
|
// Lifecycle
|
|
202
251
|
destroy: () => void;
|
|
203
252
|
resize: () => void;
|
|
204
253
|
|
|
254
|
+
// UI customization
|
|
255
|
+
setButtonLabels: (labels: Partial<ButtonLabels>) => void;
|
|
256
|
+
|
|
205
257
|
// Events
|
|
206
258
|
on: (event: ViewerEvent, callback: (...args: any[]) => void) => void;
|
|
207
259
|
off: (event: ViewerEvent, callback: (...args: any[]) => void) => void;
|
|
@@ -230,6 +282,7 @@ interface ViewerOptions {
|
|
|
230
282
|
// Lazy loading
|
|
231
283
|
lazyLoad?: boolean;
|
|
232
284
|
lazyLoadThumbnail?: string;
|
|
285
|
+
lazyLoadThumbnailType?: 'image' | 'video' | 'gif'; // Thumbnail media type
|
|
233
286
|
lazyLoadButtonText?: string;
|
|
234
287
|
}
|
|
235
288
|
```
|
|
@@ -256,6 +309,90 @@ const viewer = createViewer(container, sceneData, {
|
|
|
256
309
|
});
|
|
257
310
|
```
|
|
258
311
|
|
|
312
|
+
## Internationalization (i18n)
|
|
313
|
+
|
|
314
|
+
All user-facing UI text can be customized via `ButtonLabels`. This enables full translation or label renaming.
|
|
315
|
+
|
|
316
|
+
### At Creation Time
|
|
317
|
+
|
|
318
|
+
Set labels via `uiOptions.buttonLabels` in your scene data:
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
const sceneData = await fetch('/scene.json').then(r => r.json());
|
|
322
|
+
|
|
323
|
+
// Override labels before creating the viewer
|
|
324
|
+
sceneData.uiOptions = {
|
|
325
|
+
...sceneData.uiOptions,
|
|
326
|
+
buttonLabels: {
|
|
327
|
+
tour: 'Recorrido',
|
|
328
|
+
explore: 'Explorar',
|
|
329
|
+
walk: 'Caminar',
|
|
330
|
+
next: 'Siguiente',
|
|
331
|
+
previous: 'Anterior',
|
|
332
|
+
waypoints: 'Puntos',
|
|
333
|
+
close: 'Cerrar',
|
|
334
|
+
loading: 'Cargando...',
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
const viewer = createViewer(container, sceneData);
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### At Runtime
|
|
342
|
+
|
|
343
|
+
Update labels at any time with `setButtonLabels()`:
|
|
344
|
+
|
|
345
|
+
```javascript
|
|
346
|
+
const viewer = await createViewerFromSceneId(container, sceneId);
|
|
347
|
+
|
|
348
|
+
// Switch to Spanish
|
|
349
|
+
viewer.setButtonLabels({
|
|
350
|
+
tour: 'Recorrido',
|
|
351
|
+
explore: 'Explorar',
|
|
352
|
+
walk: 'Caminar',
|
|
353
|
+
next: 'Siguiente',
|
|
354
|
+
previous: 'Anterior',
|
|
355
|
+
close: 'Cerrar',
|
|
356
|
+
loading: 'Cargando...',
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Only update specific labels (others keep their current values)
|
|
360
|
+
viewer.setButtonLabels({ next: 'Suivant', previous: 'Pr\u00e9c\u00e9dent' });
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Available Labels
|
|
364
|
+
|
|
365
|
+
| Key | Default | Description |
|
|
366
|
+
|-----|---------|-------------|
|
|
367
|
+
| `tour` | `"Tour"` | Tour mode button |
|
|
368
|
+
| `explore` | `"Explore"` | Explore mode button |
|
|
369
|
+
| `walk` | `"Walk"` | Walk mode button |
|
|
370
|
+
| `orbit` | `"Orbit"` | Orbit sub-mode button |
|
|
371
|
+
| `fly` | `"Fly"` | Fly sub-mode button |
|
|
372
|
+
| `next` | `"Next"` | Next waypoint button |
|
|
373
|
+
| `previous` | `"Prev"` | Previous waypoint button |
|
|
374
|
+
| `startExperience` | `"Start Experience"` | Start experience button |
|
|
375
|
+
| `fullscreen` | `"Fullscreen"` | Fullscreen button aria-label |
|
|
376
|
+
| `mute` / `unmute` | `"Mute"` / `"Unmute"` | Audio toggle |
|
|
377
|
+
| `waypoints` | `"Waypoints"` | Waypoint dropdown label |
|
|
378
|
+
| `close` | `"Close"` | Hotspot popup close button |
|
|
379
|
+
| `yes` / `cancel` | `"Yes"` / `"Cancel"` | Portal confirmation buttons |
|
|
380
|
+
| `switchScenes` | `"Switch scenes?"` | Portal default prompt |
|
|
381
|
+
| `hotspotDefaultTitle` | `"Hotspot"` | Fallback hotspot title |
|
|
382
|
+
| `openExternalLink` | `"Open External Link"` | Hotspot link button text |
|
|
383
|
+
| `vr` / `ar` | `"VR"` / `"AR"` | XR button labels |
|
|
384
|
+
| `exitVr` / `exitAr` | `"Exit VR"` / `"Exit AR"` | XR exit labels |
|
|
385
|
+
| `loading` | `"Loading..."` | Loading progress text |
|
|
386
|
+
| `loadingScene` | `"Loading {name}..."` | Portal scene loading (`{name}` replaced) |
|
|
387
|
+
| `helpTitle` | `"Controls & Help"` | Help panel title |
|
|
388
|
+
| `helpCameraModes` | `"Camera Modes:"` | Help section header |
|
|
389
|
+
| `helpTourDesc` | `"Follow predefined path"` | Help tour description |
|
|
390
|
+
| `helpExploreDesc` | `"Free movement"` | Help explore description |
|
|
391
|
+
| `helpWalkDesc` | `"First-person walking"` | Help walk description |
|
|
392
|
+
| `errorWebGLTitle` | `"Unable to Initialize 3D Graphics"` | WebGL error heading |
|
|
393
|
+
| `errorWebGLMessage` | `"Your browser or device..."` | WebGL error body |
|
|
394
|
+
| `percentageFormat` | `"{n}%"` | Progress percentage format |
|
|
395
|
+
|
|
259
396
|
## Events
|
|
260
397
|
|
|
261
398
|
```javascript
|
|
@@ -282,11 +419,39 @@ viewer.on('waypointChange', ({ index, waypoint }) => {
|
|
|
282
419
|
// Playback state
|
|
283
420
|
viewer.on('playbackStart', () => console.log('Playing'));
|
|
284
421
|
viewer.on('playbackStop', () => console.log('Stopped'));
|
|
422
|
+
viewer.on('playbackComplete', () => console.log('Tour finished'));
|
|
423
|
+
|
|
424
|
+
// Camera mode
|
|
425
|
+
viewer.on('modeChange', ({ mode }) => {
|
|
426
|
+
console.log(`Camera mode: ${mode}`);
|
|
427
|
+
});
|
|
285
428
|
|
|
286
|
-
//
|
|
429
|
+
// Scroll progress
|
|
430
|
+
viewer.on('progressUpdate', ({ progress, index }) => {
|
|
431
|
+
console.log(`Progress: ${(progress * 100).toFixed(0)}%, waypoint ${index}`);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// XR sessions
|
|
435
|
+
viewer.on('xrStart', ({ type }) => console.log(`Entered ${type}`));
|
|
436
|
+
viewer.on('xrEnd', () => console.log('Exited XR'));
|
|
437
|
+
|
|
438
|
+
// Splat swap
|
|
439
|
+
viewer.on('splatChange', ({ url, isOriginal }) => {
|
|
440
|
+
console.log(`Splat changed: ${url} (original: ${isOriginal})`);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// Portal activated
|
|
444
|
+
viewer.on('portalActivated', ({ sceneId }) => {
|
|
445
|
+
console.log(`Navigating to scene: ${sceneId}`);
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Errors and warnings
|
|
287
449
|
viewer.on('error', (error) => {
|
|
288
450
|
console.error('Viewer error:', error);
|
|
289
451
|
});
|
|
452
|
+
viewer.on('warning', ({ type, message }) => {
|
|
453
|
+
console.warn(`Warning [${type}]: ${message}`);
|
|
454
|
+
});
|
|
290
455
|
```
|
|
291
456
|
|
|
292
457
|
## React Integration
|
|
@@ -415,21 +580,48 @@ function goToWaypoint(index) {
|
|
|
415
580
|
|
|
416
581
|
| Method | Description |
|
|
417
582
|
|--------|-------------|
|
|
418
|
-
|
|
|
419
|
-
| `viewer.
|
|
420
|
-
| `viewer.stop()` | Stop and reset to first waypoint |
|
|
421
|
-
| `viewer.isPlaying()` | Check if currently auto-playing |
|
|
583
|
+
| **Navigation** | |
|
|
584
|
+
| `viewer.goToWaypoint(index)` | Jump to specific waypoint (0-indexed) |
|
|
422
585
|
| `viewer.nextWaypoint()` | Go to next waypoint |
|
|
423
586
|
| `viewer.prevWaypoint()` | Go to previous waypoint |
|
|
424
|
-
| `viewer.goToWaypoint(index)` | Jump to specific waypoint (0-indexed) |
|
|
425
587
|
| `viewer.getCurrentWaypointIndex()` | Get current waypoint index |
|
|
426
588
|
| `viewer.getWaypointCount()` | Get total number of waypoints |
|
|
589
|
+
| **Camera** | |
|
|
590
|
+
| `viewer.setCameraMode(mode)` | Switch mode: `'tour'` or `'explore'` |
|
|
591
|
+
| `viewer.getCameraMode()` | Get current camera mode |
|
|
592
|
+
| `viewer.setExploreMode(mode)` | Switch explore sub-mode: `'orbit'` or `'fly'` |
|
|
427
593
|
| `viewer.setPosition(x, y, z)` | Set camera position |
|
|
428
594
|
| `viewer.setRotation(x, y, z)` | Set camera rotation (Euler angles) |
|
|
429
595
|
| `viewer.getPosition()` | Get current camera position |
|
|
430
596
|
| `viewer.getRotation()` | Get current camera rotation |
|
|
597
|
+
| **Playback / Progress** | |
|
|
598
|
+
| `viewer.play()` | Start auto-playing through waypoints |
|
|
599
|
+
| `viewer.pause()` | Pause auto-play |
|
|
600
|
+
| `viewer.stop()` | Stop and reset to first waypoint |
|
|
601
|
+
| `viewer.isPlaying()` | Check if currently auto-playing |
|
|
602
|
+
| `viewer.setProgress(progress)` | Set scroll progress (0-1) |
|
|
603
|
+
| `viewer.getProgress()` | Get current scroll progress (0-1) |
|
|
604
|
+
| **Splat Management** | |
|
|
605
|
+
| `viewer.goToSplat(url)` | Swap to a different splat file at runtime |
|
|
606
|
+
| `viewer.goToOriginalSplat()` | Switch back to the original splat |
|
|
607
|
+
| `viewer.getCurrentSplatUrl()` | Get the currently loaded splat URL |
|
|
608
|
+
| `viewer.isShowingOriginalSplat()` | Check if showing the original splat |
|
|
609
|
+
| `viewer.getAdditionalSplats()` | Get the list of additional splat swap points |
|
|
610
|
+
| **Audio** | |
|
|
611
|
+
| `viewer.muteAll()` | Mute all audio |
|
|
612
|
+
| `viewer.unmuteAll()` | Unmute all audio |
|
|
613
|
+
| `viewer.isMuted()` | Check if audio is muted |
|
|
614
|
+
| **Hotspots** | |
|
|
615
|
+
| `viewer.getHotspots()` | Get all hotspot data (id, title, type, position) |
|
|
616
|
+
| `viewer.triggerHotspot(id)` | Programmatically open a hotspot popup |
|
|
617
|
+
| `viewer.closeHotspot()` | Close the currently open hotspot popup |
|
|
618
|
+
| **Portals** | |
|
|
619
|
+
| `viewer.navigateToScene(sceneId)` | Navigate to a linked scene via portal |
|
|
620
|
+
| **Lifecycle** | |
|
|
431
621
|
| `viewer.resize()` | Recalculate canvas size (call after container resize) |
|
|
432
622
|
| `viewer.destroy()` | Clean up and remove viewer |
|
|
623
|
+
| **UI** | |
|
|
624
|
+
| `viewer.setButtonLabels(labels)` | Update UI text labels at runtime (see [i18n](#internationalization-i18n)) |
|
|
433
625
|
|
|
434
626
|
## Analytics & Tracking
|
|
435
627
|
|
|
@@ -654,7 +846,7 @@ import { generateHTML, generateHTMLFromUrl } from 'storysplat-viewer';
|
|
|
654
846
|
// From scene data object
|
|
655
847
|
const html = generateHTML(sceneData, {
|
|
656
848
|
title: 'My Scene',
|
|
657
|
-
description: 'An interactive 3D experience'
|
|
849
|
+
description: 'An interactive 3D experience',
|
|
658
850
|
});
|
|
659
851
|
|
|
660
852
|
// From scene JSON URL
|
|
@@ -668,6 +860,21 @@ import fs from 'fs';
|
|
|
668
860
|
fs.writeFileSync('scene.html', html);
|
|
669
861
|
```
|
|
670
862
|
|
|
863
|
+
#### GenerateHTMLOptions
|
|
864
|
+
|
|
865
|
+
```typescript
|
|
866
|
+
interface GenerateHTMLOptions {
|
|
867
|
+
cdnUrl?: string; // Custom CDN URL for the viewer bundle (default: unpkg)
|
|
868
|
+
title?: string; // HTML page title (default: scene name)
|
|
869
|
+
description?: string; // Meta description for SEO
|
|
870
|
+
faviconUrl?: string; // Favicon URL
|
|
871
|
+
customCSS?: string; // Custom CSS to inject into the page
|
|
872
|
+
minify?: boolean; // Minify the output HTML
|
|
873
|
+
lazyLoad?: boolean; // Show thumbnail + start button before loading
|
|
874
|
+
lazyLoadButtonText?: string; // Custom text for the lazy load button
|
|
875
|
+
}
|
|
876
|
+
```
|
|
877
|
+
|
|
671
878
|
## Portals (Scene-to-Scene Navigation)
|
|
672
879
|
|
|
673
880
|
Portals allow users to navigate between multiple 3D scenes by clicking or walking near portal markers.
|