WBC Studio#
The Studio runs the whole pipeline in one browser app — robot → data → preset → train → play — on your machine or a GPU server you reach over the network. Everything it does is also a CLI command or a file on disk, so you can switch between the GUI, the command line and scripts at any point.
Start the Studio#
$ uv run wbc-mjlab-studio
WBC Studio
→ http://192.168.x.x:8765/ from any machine on the network
→ http://127.0.0.1:8765/ this machine
Ctrl+C to stop
Open one of the links. Ctrl+C, kill or closing the terminal stops the Studio cleanly:
the playback env closes, TensorBoard stops and the ports are freed. Training and conversion
jobs are detached — they keep running and reappear on the next start.
Option |
Meaning |
|---|---|
|
Serve on every interface; |
|
UI port |
|
Network clients must open |
|
Robot to start with · torch device for playback and conversion |
|
The same Studio as a viser app (no preset editor, no robot import) |
|
Don’t open a browser tab |
Warning
Like viser, the Studio has no access control by default: anyone who can reach the port
can use it, and it can launch jobs and read local folders. Keep it on trusted networks or
start it with --token. If other machines can’t connect, open the port
(sudo ufw allow 8765/tcp). TensorBoard, started from Train, listens on the network
too (port 6006 or the next free one).
Layout#
Top bar — the pipeline: five steps (keys
1–5), each with its current state (g1 · 29 dof,samples · 22 npz,my_preset + se · 4 changes,1 running · 40%…); the robot chip; the status chip (opens the activity log); theme.3D view — whatever the current step is about: the robot and its wiring, a clip, a policy on many envs. The icon bar toggles the reference ghost, markers, labels and camera follow, and opens Plots (Plots);
?lists the keys. Over a clip or a policy, the bar at the top picks the clip, the focused env, shuffles and pushes; the transport bar at the bottom plays and scrubs.Side panel — the current step: tabs only where they help, the main action at the bottom.
1 · Robot#
Pick a robot: the built-in G1, robots of installed extensions, or robots added in the Studio. You get its model summary and tasks; Show on model draws the tracking wiring (anchor, tracked keybodies, feet), and the Pose sliders move the joints.
Add a robot#
Add robot turns a humanoid’s model files into a trainable robot — no code, no extension package. Details and the file format: Add a robot from model files.
Robot id — lowercase (
h1,my_humanoid). It names the tasks (Wbc-H1,Wbc-H1-SE) and the data folder (data/h1/).Model files — Upload folder… (the MJCF / URDF with its meshes, layout kept), Upload files…, or Copy a folder that’s on the Studio machine. Pick the model file (not a scene that includes it).
Inspect — wbc-mjlab prepares the model (removes its actuators, keyframes and floor, adds a free joint and IMU sensors when missing — listed in the panel) and suggests the wiring and gains. The 3D view shows the model with markers: anchor (amber), tracked keybodies (cyan), end-effectors (blue), feet (green).
Wiring — check the anchor, keybodies, end-effectors, feet and foot sites on the model; click body chips to change them.
Initial state — root height (the suggestion puts the feet on the floor), the sole height used to correct clip heights in conversion, joint defaults.
Actuators — effort, stiffness, damping, armature per joint. Values taken from the model are kept; others are G1-based guesses (marked
*).Check — drops the robot on a floor in its initial pose and holds it with these gains for 0.5 s (no policy): stable simulation, starts above the floor, lands on its feet, holds the pose, torque within limits.
Save robot — registers it immediately with three tasks —
Wbc-<Id>(default WBC stack),Wbc-<Id>-SE(state-estimation actor) andWbc-<Id>-Terrain-Scan(curriculum terrain + height scan under the root body) — and selects it. Edit (sliders icon) or delete (trash icon) it later from the robot list.
2 · Data#
Three tabs.
Library — datasets under data/<robot>/ with a ring for how much is converted.
Import creates a dataset from a folder of CSV / PKL clips (copy, or link without copying)
or from uploaded files. Pick a dataset to browse its clips: search with * wildcards,
filter converted / missing, page through tens of thousands of clips, tick clips for
conversion, Grid plays up to 49 clips of a search side by side. Scan computes durations
(hours, length histogram).
Clip — click a clip to play it, raw sources included, before conversion. Quality
issues: joint-limit violations, joint-speed spikes, feet below or above the ground, time
airborne. Click an issue to open it in Plots (Plots): its joints or feet
plotted against their limits, the clip paused at the first frame where it happens. The
Plots button (or j) opens the clip’s curves. For converted clips, source overlays
the raw clip as a ghost to check the conversion. [ ] step through clips.
Convert — missing, all or selected clips, output fps, batch size (parallel FK on
the GPU), mirror (needs the robot’s symmetry config), debias height, input fps. Convert N
runs wbc-mjlab-data-to-npz as a job with progress and log.
3 · Preset#
The MDP a policy learns. Start from a built-in preset (the paper setups Wbc-G1,
Wbc-G1-Zest, Wbc-G1-BinaryFailure, Wbc-G1-EE, Wbc-G1-Terrain-Scan …), switch on
modules, then change anything on these tabs:
Tab |
What you can change |
|---|---|
Observations |
Actor (policy input, also on the robot) and critic (privileged, training
only), grouped into reference (what to track), robot state and sim only. Drop
terms; Add term from every term the robot’s tasks define; scale training noise
( |
Rewards |
Weight, parameters and on / off per term, with a bar showing the split between tracking, other terms and penalties |
Terminations |
Parameters, on / off |
Sampling |
Reference state init (RSI: start sampling, adaptive bins), assistive wrench, reset noise, episode length |
Randomization |
Domain-randomization ranges, on / off |
Terrain |
Only for tasks on procedural terrain ( |
PPO |
Optimiser, rollout, network sizes |
Each change gets an amber dot (click to reset that field); the footer counts the changes against base + modules.
Modules are reusable pieces of a preset with no base task, shown as toggles under the
preset picker. The built-in se module is the state-estimation actor, read off the
<task>-SE vs <task> pair of the robot’s tasks (on G1, Wbc-G1 + se gives
exactly the Wbc-G1-SE observations). Terms a module adds are tagged with its name.
Modules apply in order, then the preset’s own changes.
Save as… stores either
a preset (trainable): base + modules + changes, trained as task
<base>--<name>, logging tologs/rsl_rl/<experiment>--<name>/; ora module: only the changes, no base — then a toggle in every preset.
Modules can be opened from the picker to edit them (built-in ones: copy with Save as module…). Apply live pushes reward weights into a running Play session to watch the terms react; training is not affected. Train saves and moves to the next step.
Files and run snapshots: Files and scripting.
4 · Train#
The preset and dataset come from the previous steps (each with a shortcut back). Set the
budget (envs, iterations — or the 1k / 5k / 30k / 100k chips), a run name, the logger
(TensorBoard / W&B), fresh or continue from a run’s checkpoint; Advanced takes extra
arguments and shows the exact command line. Launch starts a detached job
(wbc-mjlab-train, or python -m wbc_mjlab.studio.train_preset for your presets — single
GPU).
Jobs lists training and conversion jobs. A job shows progress and ETA, curves (reward, tracking errors, per-term rewards, sampling, losses), the log, TensorBoard, Stop / Forget, and Play for its run.
5 · Play#
Pick a run (or the bundled demo checkpoint) and a checkpoint — or the zero action (the PD holds the reference: judge a dataset without a policy) — a motion library and the number of envs (1, 4, 16, 64, or any count up to 4096 typed in the box), then Load policy. Every env shows its reference ghost (aligned to the robot’s xy + yaw, as the body rewards compare, or in world frame to see drift) and keybody targets coloured by error. The focused env’s reward terms and a HUD (return, body / joint error, anchor drift, episode time) update live; Tune jumps to the rewards. The bar over the 3D view picks the focused env’s clip (it loops), shuffles the others and pushes the robot. Click a robot (or its label) to focus it. Another checkpoint swaps in place; envs that blow up are reset automatically.
Session changes the running session without reloading the policy: Environments resizes it at once up to the envs already built (a power of two, at least 16; more rebuilds it in the background), and Terminations switches on or off live (off: no episode ends, time-outs included).
On terrain tasks (-Terrain-Scan) each env stands on a tile of its own terrain, sampled
from the simulation and following the robot — grey flat, rising towards teal; envs are spread
over every difficulty row, as in wbc-mjlab-play.
Runs of your own presets are rebuilt from their snapshot (params/studio_preset.yaml), so
they replay as trained even after the preset changed.
Plots#
The chart icon in the 3D view’s icon bar (or j) opens Plots: a window over the stage you can drag, resize and make full screen (F). It plots what the stage shows:
Stage |
Channels |
Dashed |
|---|---|---|
Data — one clip |
Root position, root roll / pitch / yaw, root speed (horizontal), every joint (with its limits), the feet’s sole heights |
A converted clip’s raw source, resampled to the clip’s frames: what conversion changed |
Play — the focused env |
The robot’s root and joints, PD targets, joint torques (the motor’s, with its effort limits; the friction a Unitree actuator takes off it as its own group), actions, per-keybody tracking error, every reward term weighted (as summed into the reward, with the total) and raw (before the weight: the tracking kernels in [0, 1]) |
The reference the policy tracks — for each row, the frame that step’s rewards compared the robot to |
Pick up to eight channels from the list (search, or plot a whole group — for rewards the largest contributors); each keeps its colour while plotted. One plot shows one unit: picking a channel of another unit (an angle after a torque) starts a new plot rather than adding a second y-axis.
Compare — Reference draws the reference dashed next to each channel; Error plots actual − reference instead. The legend shows each channel’s RMSE against its reference over the visible time span; the tooltip reads actual, reference and their difference.
Time — scroll to zoom, Shift-drag to pan, Ctrl-drag (or Zoom) a box to zoom time and values, double-click to see everything; from / to sets an exact range in seconds. On a clip, dragging scrubs the clip and the stage follows; setting a range moves the clip there.
Play — the window shows the last 60 s of the focused env and follows the newest steps (Live, over the last 5–60 s), updated with every stage frame; a click pins a cursor to read a moment while the policy keeps running. Dashed lines mark each new episode or clip, with the clip’s name. Every env of a session of up to 32 envs is recorded, so focusing another env (also while paused) shows its record at once; in a larger session an env records from when it is first focused.
Units — Pos / Vel / Acc (finite differences, not across episode boundaries) and deg / rad for joint and root channels; Limits shades the joint limits — and, for joint torques, the effort limits: the tightest of the asset’s
actuatorfrcrange/ actuatorforcerange(× gear), the actuator’seffort_limitand, for Unitree actuators, the peak of the torque–speed envelope (lower at speed). The status line counts the frames outside the joint limits, or at the effort limit (saturated).Table view — the download button saves the plotted channels (and their references) as CSV.
Files and scripting#
The Studio keeps its own files per user, outside the repo, in ~/.config/wbc-mjlab/
(presets/, modules/, robots/); jobs live in logs/studio/jobs/, runs in
logs/rsl_rl/ as usual. Presets are short YAML diffs you can edit by hand or train
without the Studio:
uv run python -m wbc_mjlab.studio.train_preset --preset my_preset --dataset samples
Every training run of a preset keeps the preset as trained in params/studio_preset.yaml,
so editing or deleting a preset never changes how older runs replay.
Note
Two meanings of preset: code presets (apply_wbc, apply_zest …) build the
registered tasks; a Studio preset is a YAML diff on top of one of those tasks. See
Presets and tasks.
File formats: Configuration and files
Everything the GUI does is a JSON call — script it: Studio HTTP API
viser version#
--ui viser serves the same core as a viser app (Robot, Data, Train and Play tabs). The
preset editor, modules and robot import are web-only.
See also
Prepare motion data · Train a policy · Evaluate and visualize — the same steps in depth
Add a robot from model files — what Add robot does
Troubleshooting — Studio not reachable, port in use, failing robot check