Client Handles¶
- class viser.ClientHandle[source]¶
A handle is created for each client that connects to a server. Handles can be used to communicate with just one client, as well as for reading and writing of camera state.
Similar to
ViserServer, client handles also expose scene and GUI interfaces atClientHandle.sceneandClientHandle.gui. If these are used, for example via a client’sSceneApi.add_point_cloud()method, created elements are local to only one specific client.Client state is ephemeral. A client handle corresponds to a single websocket connection: when the browser disconnects or reloads, elements created through the handle are gone, and the reconnected browser is a new client (new handle, new
client_id). Per-client state should therefore be (re)built inViserServer.on_client_connect(), which fires again on reconnect. State that must outlive a connection belongs client-side (browser storage) or in application code keyed however the application identifies its users; the server never retains per-client element state.Scene names shadow, not collide. Each scene-tree name holds at most one node per scope: adding a client-scoped node under a name the server also uses creates an independent per-client variant that shadows the server’s node for this one client (the server’s node, with its latest state, shows again when the client-scoped variant is removed). State is fully scope-local – updates and removals from one scope never touch the other scope’s variant, and removing a node cascades only through its own scope’s descendants. A client-scoped node may be named under a server-scoped parent (e.g. per-client annotations under a shared frame); it survives the parent’s removal, anchored at the parent’s last pose, until this handle removes it.
GUI containers nest one way. A client-scoped GUI element may be added inside a server-scoped container context (
with server.gui.add_folder(...): client.gui.add_button(...)); it renders inside the shared folder for this client only, and is removed along with the folder. The reverse – a server-scoped element inside a client-scoped container – raises, since no other client could see the container.- camera: CameraHandle¶
Handle for reading from and manipulating the client’s viewport camera.
- local_storage: LocalStorageHandle¶
Handle for reading and writing the client’s browser localStorage.
- flush() None[source]¶
Flush the outgoing message buffer. Any buffered messages will immediately be sent. (by default they are windowed)
- Return type:
None
- atomic() ContextManager[None][source]¶
Returns a context where: all outgoing messages are grouped and applied by clients atomically.
This should be treated as a soft constraint that’s helpful for things like animations, or when we want position and orientation updates to happen synchronously.
- Returns:
Context manager.
- Return type:
ContextManager[None]
- send_file_download(filename: str, content: bytes, chunk_size: int = 1048576, save_immediately: bool = False) None[source]¶
Send a file for a client or clients to download.
- Parameters:
filename (str) – Name of the file to send. Used to infer MIME type.
content (bytes) – Content of the file.
chunk_size (int) – Number of bytes to send at a time.
save_immediately (bool) – Whether to save the file immediately. If False, a link to the file will be shown as a notification. Being able to right click the link and choose “Save as…” can be useful.
- Return type:
None
- add_notification(title: str, body: str, *, loading: bool = False, with_close_button: bool = True, auto_close_seconds: float | None = None, color: Literal['dark', 'gray', 'red', 'pink', 'grape', 'violet', 'indigo', 'blue', 'cyan', 'green', 'lime', 'yellow', 'orange', 'teal'] | tuple[int, int, int] | None = None) NotificationHandle[source]¶
- add_notification(title: str, body: str, *, loading: bool = False, with_close_button: bool = True, auto_close: int | Literal[False] = False, color: Literal['dark', 'gray', 'red', 'pink', 'grape', 'violet', 'indigo', 'blue', 'cyan', 'green', 'lime', 'yellow', 'orange', 'teal'] | tuple[int, int, int] | None = None) NotificationHandle
Add a notification to the client’s interface.
This method creates a new notification that will be displayed at the top left corner of the client’s viewer. Notifications are useful for providing alerts or status updates to users.
Deprecated since version 1.0.0: The auto_close argument is deprecated. Use auto_close_seconds instead.
- Parameters:
title – Title to display on the notification.
body – Message to display on the notification body.
loading – Whether the notification shows loading icon.
with_close_button – Whether the notification can be manually closed.
auto_close_seconds – Time before the notification automatically closes; None if the notification does not close on its own.
- Returns:
A handle that can be used to interact with the GUI element.
- get_render(height: int, width: int, *, wxyz: tuple[float, float, float, float] | ndarray, position: tuple[float, float, float] | ndarray, fov: float, transport_format: Literal['png', 'jpeg'] = 'jpeg', timeout: float | None = None) ndarray[source]¶
- get_render(height: int, width: int, *, transport_format: Literal['png', 'jpeg'] = 'jpeg', timeout: float | None = None) ndarray
Request a render from a client, block until it’s done and received, then return it as a numpy array. If wxyz, position, and fov are not provided, the current camera state will be used.
- Parameters:
height – Height of rendered image. Should be <= the browser height.
width – Width of rendered image. Should be <= the browser width.
wxyz – Camera orientation as a quaternion. If not provided, the current camera position will be used.
position – Camera position. If not provided, the current camera position will be used.
fov – Vertical field of view of the camera, in radians. If not provided, the current camera position will be used.
transport_format – Image transport format. JPEG (default) returns a lossy (H, W, 3) RGB array with a small payload on any content. PNG returns a lossless (H, W, 4) RGBA array with a transparent background, but can cause memory issues on the frontend if called too quickly for higher-resolution images.
timeout – Optional maximum seconds to wait for the frame.
None(default) waits indefinitely; a disconnect still raises promptly either way. Set this to bound a client that stays connected but never returns a frame (raisesTimeoutError).
Note
Captures reflect all scene state updates (poses, colors, visibility, geometry props) made before the call. Content that the browser decodes or loads asynchronously – large background/image textures, GLB assets, environment maps – is not awaited: a capture issued immediately after such an update may still show the previous content if the decode hasn’t finished (more likely on fast displays, where frames are short relative to decode time). When that matters, capture after the asset has had a moment to load.
- class viser.LocalStorageHandle[source]¶
A handle for reading and writing this client’s browser localStorage.
Keys are namespaced in the browser under a viser-specific prefix, so values written here can’t collide with — and
clear()can’t wipe — localStorage state that other applications keep on the same origin. The prefix is an implementation detail: keys passed to these methods should be the bare, unprefixed names.- get_item(key: str, timeout: float | None = None) str | None[source]¶
Return a value, or
Noneif the key is absent.Failure semantics match
ClientHandle.get_render().- Parameters:
- Raises:
RuntimeError – If the client disconnects before responding, or if the browser blocks localStorage access.
TimeoutError – If
timeoutis set and exceeded.
- Return type:
str | None