Skip to main content

body-models-viser

Browser-side body model evaluation for viser.

Python owns the body model asset loaders and the prepare_identity() / prepare_pose() calls. TypeScript owns the browser model lifecycle and WASM buffers. Rust owns the stateless fallback kernels.

Usage

Skinned Body Models

Use add_body_model() for any body_models.SkinnedModel, including SMPL, SMPL-X, MANO, FLAME, MHR, SOMA, SKEL, ANNY, and GarmentMeasurements.

import body_models_viser as bmv
import viser
from body_models.smpl.numpy import SMPL

server = viser.ViserServer()
model = SMPL(gender="neutral")
handle = bmv.add_body_model(server.scene, "/smpl", model, color=(173, 216, 230))

pose = handle.body_pose.copy()
pose[2, 0] = 0.5
handle.body_pose = pose

translation = handle.global_translation.copy()
translation[1] = 0.25
handle.set_transform(global_translation=translation)

shape = handle.shape.copy()
shape[0] = 1.0
handle.set_identity(shape=shape)

# Apply an additional scene-node transform after the body-model transform.
handle.position = (0.0, 0.0, 0.5)
handle.wxyz = (1.0, 0.0, 0.0, 0.0)
handle.visible = False

add_body_model() returns a generic handle with set_identity(...), set_pose(...), set_transform(...), remove(), visible, position, wxyz, global_rotation, global_translation, and the parameter properties declared by the model. position and wxyz are scene-node deltas applied after the body-model's global transform.

Pose correctives are disabled by default. Enable them explicitly when their visual fidelity is needed:

handle = bmv.add_body_model(
    server.scene,
    "/smpl",
    model,
    use_pose_correctives=True,
)

Correctives are evaluated in the client. Enabling them sends the model's dense or sparse corrective basis once per shared asset, quantized to signed 16-bit values, then sends only the small coefficient vector on each pose update. The basis is not retransmitted per body or frame. Browser clients receive this model data, so applications must ensure that doing so is compatible with the asset's license.

Skeletons

Use add_skeleton() for a standalone clickable skeleton. It takes joint positions and a parent index for each joint.

import body_models_viser as bmv

pose = model.get_rest_pose()
skeleton = model.forward_skeleton(**pose)
joint_positions = skeleton[:, :3, 3]

handle = bmv.add_skeleton(
    server.scene,
    "/skeleton",
    joint_positions,
    model.parents,
    joint_names=tuple(model.joint_names),
)

handle.visible = True
handle.joint_positions = joint_positions

Runtime

bmv.add_body_model(scene, name, model) does three things:

  1. Injects body-models-viser.js and body-models-viser.wasm.
  2. Sends shared topology and sparse skin weights once, followed by the current identity and pose as little-endian binary buffers.
  3. Returns a body model handle.

handle.set_identity(...) sends rest vertices and pose state. handle.set_pose(...) sends only joint transforms and, when requested, pose coefficients. handle.set_transform(...) sends only the global transform. Without correctives, Rust applies sparse linear-blend skinning in WASM. With correctives, a fused WebGPU kernel evaluates the corrective basis and skinning together; the runtime falls back to WASM when WebGPU is unavailable. Both paths preserve the basis representation exposed by body-models: dense bases remain dense, while sparse bases remain sparse. The resulting vertex buffer is sent to viser as a regular mesh message.

The browser protocol is model-agnostic. It consumes only the public SkinningSpec and prepared identity and pose state from body-models 0.24.1 or newer.

viser compatibility

This package patches viser private internals (message serializer, websock client state, and the client React tree) to inject its runtime. The supported minimum is viser 1.1.0. When raising it, run uv run pytest and uv run scripts/visualize_models.py against the new minimum, then check that a browser renders the body model.

Development

Build the Rust crate:

cargo test

Build the browser bundle and WASM:

cd client
npm ci
npm test

The browser build requires a Rust toolchain with wasm32-unknown-unknown installed, for example:

rustup target add wasm32-unknown-unknown

Run the small visualizer:

uv run --no-sync scripts/visualize_models.py

Check NumPy/WASM vertex parity for all supported models:

uv run scripts/check_model_parity.py

Stress ten full-resolution SMPL-X bodies at 60 FPS:

OPENBLAS_NUM_THREADS=1 uv run scripts/stress_smplx.py
OPENBLAS_NUM_THREADS=1 uv run scripts/stress_smplx.py --use-pose-correctives

In the browser console, BodyModelsViser.stats() reports render FPS, model update FPS, the corrective backend, and corrective batch time.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

body_models_viser-0.7.1.tar.gz (61.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

body_models_viser-0.7.1-py3-none-any.whl (34.8 kB view details)

Uploaded Python 3

File details

Details for the file body_models_viser-0.7.1.tar.gz.

File metadata

  • Download URL: body_models_viser-0.7.1.tar.gz
  • Upload date:
  • Size: 61.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for body_models_viser-0.7.1.tar.gz
Algorithm Hash digest
SHA256 469af8bfd8684d80bfc405316a13a8898932e0711f37dd95a9a4dd4bec2873a4
MD5 5973a8e01e2e3fc98e8e65509ff04bd1
BLAKE2b-256 cd06c853651501fbba846155757d1d63dbd6704325c5f80cedb4fcee10bb941e

See more details on using hashes here.

File details

Details for the file body_models_viser-0.7.1-py3-none-any.whl.

File metadata

  • Download URL: body_models_viser-0.7.1-py3-none-any.whl
  • Upload date:
  • Size: 34.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for body_models_viser-0.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a3720f8786fb665e228de3d89862a6fc3e6d10a9247e2044c6105c97b622da00
MD5 7d1238c9c56c9b87c8d047a89f43dcb1
BLAKE2b-256 9d877f80ff18e236b97b1e92a2e46625b716149af7a1a596b8616bae95db6cb1

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.7.1 This release

2 files

0.6.1

2 files

0.6.0

2 files

0.5.1

2 files

0.5.0

2 files

0.4.3

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.5

2 files

0.3.4

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.0.2

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page