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 at ClientHandle.scene and ClientHandle.gui. If these are used, for example via a client’s SceneApi.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 in ViserServer.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.

client_id: int

Unique ID for this client.

scene: SceneApi

Handle for interacting with the 3D scene.

gui: GuiApi

Handle for interacting with the GUI.

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 (raises TimeoutError).

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.

set_item(key: str, value: str) None[source]

Set a key.

Parameters:
Return type:

None

remove_item(key: str) None[source]

Remove a key.

Parameters:

key (str)

Return type:

None

get_item(key: str, timeout: float | None = None) str | None[source]

Return a value, or None if the key is absent.

Failure semantics match ClientHandle.get_render().

Parameters:
  • key (str) – Key to read.

  • timeout (float | None) – Optional maximum seconds to wait for the value. None (default) waits indefinitely; a disconnect still raises promptly either way. Set this to bound a client that stays connected but never returns a response (raises TimeoutError).

Raises:
  • RuntimeError – If the client disconnects before responding, or if the browser blocks localStorage access.

  • TimeoutError – If timeout is set and exceeded.

Return type:

str | None

class viser.NotificationHandle[source]

Handle for a notification in our visualizer.

remove() None[source]
Return type:

None

title: str

Title of the notification.

body: str

Body text of the notification.

loading: bool

Whether to show a loading indicator.

with_close_button: bool

Whether to show a close button.

auto_close_seconds: float | None

Time in seconds after which the notification should auto-close, or False to disable auto-close.

color: LiteralColor | Tuple[int, int, int] | None

Color of the notification.