Embedding Visualizations¶
This guide describes how to export 3D visualizations from Viser and embed them into static webpages. The process involves three main steps: exporting scene state, creating a client build, and hosting the visualization.
Warning
This workflow is experimental and not yet polished. We’re documenting it nonetheless, since we think it’s quite useful! If you have suggestions or improvements, issues and PRs are welcome.
Step 1: Exporting Scene State¶
You can export static or dynamic 3D data from a Viser scene using the scene
serializer. ViserServer.get_scene_serializer()
returns a serializer
object that can serialize the current scene state to a binary format.
Static Scene Export¶
For static 3D visualizations, StateSerializer.serialize()
can be used to
save the scene state:
import viser
from pathlib import Path
server = viser.ViserServer()
# Add objects to the scene via server.scene
# For example:
# server.scene.add_mesh(...)
# server.scene.add_point_cloud(...)
server.scene.add_box("/box", color=(255, 0, 0), dimensions=(1, 1, 1))
# Serialize and save the scene state
data = server.get_scene_serializer().serialize() # Returns bytes
Path("recording.viser").write_bytes(data)
As a suggestion, you can also add a button for exporting the scene state.
Clicking the button in your web browser wil trigger a download of the
.viser
file.
import viser
server = viser.ViserServer()
# Add objects to the scene via server.scene.
# For example:
# server.scene.add_mesh(...)
# server.scene.add_point_cloud(...)
server.scene.add_box("/box", color=(255, 0, 0), dimensions=(1, 1, 1))
save_button = server.gui.add_button("Save Scene")
@save_button.on_click
def _(event: viser.GuiEvent) -> None:
assert event.client is not None
event.client.send_file_download("recording.viser", server.get_scene_serializer().serialize())
server.sleep_forever()
Dynamic Scene Export¶
For dynamic visualizations with animation, you can create a “3D video” by
calling StateSerializer.insert_sleep()
between frames:
import viser
import numpy as np
from pathlib import Path
server = viser.ViserServer()
# Add objects to the scene via server.scene
# For example:
# server.scene.add_mesh(...)
# server.scene.add_point_cloud(...)
box = server.scene.add_box("/box", color=(255, 0, 0), dimensions=(1, 1, 1))
# Create serializer.
serializer = server.get_scene_serializer()
num_frames = 100
for t in range(num_frames):
# Update existing scene objects or add new ones.
box.position = (0.0, 0.0, np.sin(t / num_frames * 2 * np.pi))
# Add a frame delay.
serializer.insert_sleep(1.0 / 30.0)
# Save the complete animation.
data = serializer.serialize() # Returns bytes
Path("recording.viser").write_bytes(data)
Note
Always add scene elements using ViserServer.scene
, not ClientHandle.scene
.
Note
The .viser
file is a binary format containing scene state data and is not meant to be human-readable.
Step 2: Creating a Viser Client Build¶
To serve the 3D visualization, you’ll need two things:
The
.viser
file containing your scene dataA build of the Viser client (static HTML/JS/CSS files)
With Viser installed, create the Viser client build using the command-line tool:
# View available options
viser-build-client --help
# Build to a specific directory
viser-build-client --output-dir viser-client/
Step 3: Hosting¶
Directory Structure¶
For our hosting instructions, we’re going to assume the following directory structure:
.
├── recordings/
│ └── recording.viser # Your exported scene data
└── viser-client/
├── index.html # Generated client files
├── assets/
└── ...
This is just a suggestion; you can structure your files however you like.
Local Development Server¶
For testing locally, you can use Python’s built-in HTTP server:
# Navigate to the parent directory containing both folders
cd /path/to/parent/dir
# Start the server (default port 8000)
python -m http.server 8000
Then open your browser and navigate to:
http://localhost:8000/viser-client/
(default port)
This should show the a standard Viser client. To visualize the exported scene, you’ll need to specify a URL via the ?playbackPath=
parameter:
http://localhost:8000/viser-client/?playbackPath=http://localhost:8000/recordings/recording.viser
GitHub Pages Deployment¶
To host your visualization on GitHub Pages:
Create a new repository or use an existing one
Create a
gh-pages
branch or enable GitHub Pages on your main branchPush your directory structure to the repository:
git add recordings/ viser-client/ git commit -m "Add Viser visualization" git push origin main # or gh-pages
Your visualization will be available at: https://user.github.io/repo/viser-client/?playbackPath=https://user.github.io/repo/recordings/recording.viser
You can embed this into other webpages using an HTML <iframe />
tag.
Step 4: Setting the initial camera pose¶
To set the initial camera pose, you can add a &logCamera
parameter to the URL:
http://localhost:8000/viser-client/?playbackPath=http://localhost:8000/recordings/recording.viser&logCamera
Then, open your Javascript console. You should see the camera pose printed whenever you move the camera. It should look something like this:
&initialCameraPosition=2.216,-4.233,-0.947&initialCameraLookAt=-0.115,0.346,-0.192&initialCameraUp=0.329,-0.904,0.272
You can then add this string to the URL to set the initial camera pose.