# Browser-Based Robotics Simulation and Online Physics for G1



## Executive summary


If your goal is to get a **Unitree G1** running *in a browser*, the strongest practical options split into three tiers. **For highest fidelity and direct use of G1’s existing MJCF assets, MuJoCo’s official JavaScript/WebAssembly bindings are the best fit**: MuJoCo natively loads **MJCF and URDF**, its web bindings are now official, and the bindings expose a workable file-system model for loading XML assets in-browser. Unitree’s own G1 description package explicitly ships **URDF and MJCF** variants, so the asset path is already aligned. The trade-off is that the web bindings are still marked **work in progress**, and you still need to build a small upload/asset-loading wrapper yourself. citeturn14view1turn15view1turn19view0


If you want the **fastest path to “a standing G1 in the browser”**, **Three.js + URDFLoader** is the easiest route. It is effectively a browser-native robot viewer with joint control, drag-and-drop examples, package-path handling, and custom mesh-loading hooks. It is, however, **visualisation rather than serious physics**, so it is ideal for posture, sliders, demos, and UI work, but not for balance or contact-rich locomotion. citeturn16view0turn16view1turn19view0


If you want **basic browser-native physics** without bringing in MuJoCo, **Three.js + Rapier** is the best lightweight compromise. Rapier has official WebAssembly/JavaScript support, joints, browser demos, and a modern, actively maintained stack. The downside is that it does **not** natively ingest MJCF or URDF as a robotics simulator would; you have to map robot structure into colliders, rigid bodies, and joints yourself, or build a converter. citeturn1view2turn30view0turn20search4


For **cloud-hosted browser access**, the picture is different. **Isaac Sim** and **Gazebo/GzWeb** are not browser-native simulators; they are server-side simulators with a browser or streaming front end. Isaac Sim is powerful and can import **URDF and MJCF**, but it is operationally heavy and server/GPU-centric. GzWeb is a thin web client for Gazebo, but the reviewed documentation is tied to **Gazebo Classic**, which is already at end-of-life. **Webots.cloud** is mature and open, but its workflow is centred on **Webots projects hosted from GitHub**, and for URDF robots it generally expects conversion into Webots’ own workflow rather than direct MJCF ingestion. citeturn24view0turn24view1turn24view2turn31view0turn31view1turn21view1turn22search3


For **ONNX policies**, there is no reviewed browser robotics platform that offers a polished “upload robot + upload locomotion ONNX + run” workflow out of the box. The enabling technology does exist: **ONNX Runtime Web** supports in-browser inference via **WASM, WebGPU, WebGL, and WebNN**, with WASM covering all ONNX operators and GPU back ends covering subsets. In practice, this means that browser-native approaches can run ONNX policies, but you still have to implement observation extraction, normalisation, action mapping, and the simulation loop yourself. citeturn25view0turn25view1turn25view2


The overall recommendation is straightforward. If you need **real G1 physics and direct MJCF reuse**, choose **MuJoCo WASM**. If you need **something working today with minimal friction**, choose **Three.js + URDFLoader**. If you need **basic interactions and contacts in a lightweight browser stack**, choose **Three.js + Rapier**. citeturn14view1turn16view0turn30view0


## Landscape and evaluation criteria


The most important distinction is between **browser-native** and **cloud-hosted** approaches. Browser-native stacks run physics and rendering on the client using JavaScript or WebAssembly. That generally improves privacy, avoids streaming latency, and makes local file workflows easier. Cloud-hosted stacks run the simulator on a server and expose either a thin web client or a streamed viewer; they unlock heavier engines, but add operational overhead, data-placement concerns, and usually some form of server or GPU cost. citeturn25view1turn24view0turn31view1


For **physics engines**, the relevant browser-native families in this review are: **MuJoCo WASM** through the official `@mujoco/mujoco` package; **Rapier** through official WebAssembly/JavaScript bindings; **Ammo.js** as a direct Emscripten port of **Bullet**; and **PhysX** only through community-made WebAssembly bindings rather than a first-party NVIDIA browser package. For classic robotics simulators, **Gazebo** exposes **ODE, Bullet, Simbody, and DART** on the server side, while **Webots** uses an **ODE fork**. Isaac Sim is built around **PhysX** and offers browser access through streaming rather than browser-native execution. citeturn14view1turn1view2turn1view3turn27view0turn31view2turn28search0turn24view0turn27view1


For **model import**, the decisive question is whether the platform accepts **URDF, MJCF, SDF, glTF, or STL** as first-class inputs. MuJoCo loads **MJCF and URDF**, and its mesh pipeline supports **STL, OBJ, and MSH**. Isaac Sim imports **URDF and MJCF**, and NVIDIA explicitly documents additional mesh import paths including **OBJ, FBX, STL, and glTF** into USD. Webots is friendlier to **Webots worlds/PROTO** but provides an official **URDF-to-Webots** converter. GzWeb inherits Gazebo’s server-side world model rather than acting as a standalone browser importer. By contrast, Rapier, Ammo.js, and PhysX WASM are **physics kernels**, not robotics import pipelines: they do not natively give you URDF/MJCF robotics workflows. citeturn2search9turn2search3turn24view2turn8search8turn22search3turn31view1


For **G1 specifically**, Unitree’s official description package is a major advantage because it already provides **URDF & MJCF** forms of the robot and shows STL mesh references in the package. That makes MuJoCo WASM and URDF-based viewers much more realistic than starting from scratch. None of the reviewed browser-facing platforms advertises a first-class “Unitree G1” template, so support is mostly **generic asset compatibility**, not robot-specific tooling. citeturn19view0


For **ONNX and custom controllers**, ONNX Runtime Web is now mature enough to make in-browser policy inference realistic. It supports browser-side inference with **WASM**, and optionally **WebGPU/WebGL/WebNN**. ONNX Runtime’s own guidance is explicit that browser inference can improve privacy, work offline, and reduce serving cost for appropriately sized models, while server inference is better when models are too large or you do not want them downloaded to the client. That makes browser-native ONNX execution technically viable for G1 policies, provided the model’s operators are supported by the chosen execution provider and you know the observation/action contract. citeturn25view0turn25view1turn25view2


## Comparison of candidate options


| Name | Type | Engines supported | Model formats accepted | ONNX/controller support | Ease of use | Cost/licence | Notes & links |

|---|---|---|---|---|---:|---|---|

| **MuJoCo JS/WASM** | Browser-native | MuJoCo WASM | **MJCF, URDF**; meshes incl. **STL/OBJ/MSH** | **Yes**, via JS control loop; ONNX possible through separate ONNX Runtime Web integration | **3** | Free, **Apache-2.0** | Best fit for G1’s existing MJCF assets; official bindings are canonical but still marked **WIP**. Multi-threading is available with `SharedArrayBuffer` and COOP/COEP headers. citeturn14view1turn26view0turn15view1turn2search3turn2search9 |

| **Three.js + URDFLoader** | Browser-native | No physics by default | **URDF**; package-path support; custom mesh callbacks can load e.g. glTF meshes | **Yes**, for custom JS UI/controllers; ONNX possible via separate web inference, but no physics engine underneath | **5** | Free; URDFLoader **Apache-2.0** | Fastest route to a visible G1 with sliders. Ideal for posture, inspection, demos, and editor-like tooling. citeturn16view0turn16view1turn20search3turn4search1 |

| **Three.js + Rapier** | Browser-native | **Rapier** | Native geometry/glTF workflows; **URDF/MJCF require custom conversion/parsing** | **Yes**, custom JS loop; ONNX Runtime Web integrates cleanly | **3** | Free, **Apache-2.0** | Best lightweight middle ground: official WASM bindings, joints, demos, SIMD/parallelism, browser support. Not a robotics-format-first simulator. citeturn1view2turn30view0turn20search4turn25view1 |

| **Babylon.js + Ammo.js** | Browser-native | **Ammo.js** = Bullet port | Babylon meshes / glTF workflows; robotics formats need custom parsing | **Yes**, custom JS logic; ONNX possible separately | **2** | Babylon.js **Apache-2.0**; Ammo.js **zlib** | Viable for browser physics, but Ammo.js is fundamentally a general Bullet port, not a robot-import stack. Ammo.js upstream is based on **Bullet 2.82 patched with a 2.83 fix**. citeturn23search8turn32search0turn1view3 |

| **PhysX WASM via `physx-js-webidl`** | Browser-native | **PhysX** | No native robotics import workflow; custom loaders/conversion needed | **Yes**, custom JS loop; ONNX possible separately | **2** | Community binding **MIT**; official PhysX SDK **BSD-3-Clause** | Interesting technically, especially for articulations, but this is **community-maintained**, not a first-party NVIDIA browser product. citeturn27view0turn27view1turn20search5 |

| **Webots.cloud** | Cloud-hosted in browser | **ODE fork** via Webots | Webots projects; **URDF via official conversion/import tools**; MJCF not documented as native | Controllers run **server-side**; in-browser ONNX not documented | **2** | Webots/Webots.cloud open source, **Apache-2.0**; hosted pricing **unspecified** in reviewed docs | Good for sharing complete simulations from GitHub; workflow is repository-centric, not drag-and-drop MJCF. `publish: false` exists for non-public sync behaviour. citeturn21view1turn28search0turn20search18turn22search3 |

| **Gazebo + GzWeb** | Cloud-hosted thin web client | Gazebo server with **ODE, Bullet, Simbody, DART** | Gazebo workflow and model database; not direct browser upload; **MJCF not native** | Controllers/plugins run **server-side**; browser is thin client | **1** | Free, **Apache-2.0** | Technically capable, but the reviewed GzWeb docs are tied to **Gazebo Classic**, which reached **EOL in Jan 2025**. citeturn31view2turn31view1turn31view0 |

| **Isaac Sim streamed to browser** | Cloud-hosted/streamed | **PhysX** | **URDF, MJCF**, plus importers for **OBJ, FBX, STL, glTF** into USD workflows | Custom controllers run **server-side**; browser viewer itself is not the compute environment | **2** | Isaac Sim free/open source under **Apache-2.0** with additional NVIDIA terms; GPU/cloud costs apply | Very capable, but operationally heavy. Browser viewer is via Web-based viewer/WebRTC; NVIDIA documents high GPU requirements and NVENC constraints. citeturn24view0turn24view1turn24view2turn24view3turn24view4 |


**Interpretation of the table.** Browser-native options win on privacy, deployment simplicity, and local iteration. Cloud-hosted options win on simulator sophistication, sensor fidelity, and existing robotics tooling, but lose on convenience and cost. For G1, **MuJoCo JS/WASM** is the only reviewed browser-native option that cleanly matches the **official MJCF/URDF assets** without a format pivot. citeturn19view0turn25view1turn24view0


## Findings by dimension


On **physics fidelity**, browser-native stacks split into two classes. MuJoCo WASM exposes a real robotics engine; Rapier, Ammo.js, and PhysX WASM are general-purpose rigid-body engines that can be used for robots but do not ship a robotics-model ingestion layer. That distinction matters more than raw engine quality. For a humanoid like G1, the hard part is not only stepping physics; it is importing articulated structure, meshes, inertias, contacts, and controller semantics consistently. citeturn2search9turn15view1turn30view0turn1view3turn27view0


On **file import and workflow**, MuJoCo’s official bindings are more browser-friendly than they first appear. The official test suite shows XML being written into the Emscripten virtual file system with `FS.writeFile()` and then loaded via `MjModel.mj_loadXML()`. That means a browser-side “upload MJCF + upload meshes + run” flow is entirely plausible. The caveat is that you build the UX yourself; there is no official managed upload web app in the reviewed documentation. citeturn15view0turn15view1


On **ease of loading G1**, the official Unitree package is the key enabler. Unitree documents G1 as a package with **URDF & MJCF**, including many G1 variants, and even shows MuJoCo drag-and-drop visualisation for those XML files. That makes MuJoCo WASM and URDF visualisation straightforward in principle. By contrast, Rapier, Ammo.js, and PhysX require a conversion layer from your URDF or MJCF into runtime bodies and joints. citeturn19view0turn30view0turn1view3turn27view0


On **ONNX policy execution**, the browser story is now good enough for serious experimentation. ONNX Runtime Web supports **WASM** and can optionally use **WebGPU**, while ONNX’s own guidance notes that browser inference can be faster, more private, offline-capable, and cheaper for suitable workloads. It also states that **WASM supports all ONNX operators**, whereas GPU-oriented execution providers only support subsets. For a locomotion policy, that means in-browser inference is viable as long as the model is modest enough and you implement the surrounding robotics plumbing. citeturn25view1turn25view2turn25view0


On **performance**, the cleanest rule is this: **browser-native physics avoids streaming latency but is bounded by the client device**, while **cloud-hosted simulators offload computation but introduce server cost, network setup, and video-streaming overhead**. MuJoCo’s web package offers both single-threaded and multi-threaded builds, with the latter requiring cross-origin isolation headers. Rapier explicitly advertises **SIMD and parallelism**. ONNX Runtime Web recommends WebGPU for more compute-intensive models and keeps WASM as the baseline for lighter ones. Isaac Sim, on the other hand, documents substantial GPU requirements, notes that GPUs with under 16 GB VRAM may be insufficient for demanding scenes, and requires **NVENC** for livestreaming. citeturn26view0turn30view0turn25view2turn24view0turn24view3


On **security and privacy**, browser-native stacks are materially better when the app is designed to keep files local. Standard browser file APIs allow pages to work with user-selected local files, and ONNX Runtime specifically highlights privacy benefits because inference data need not leave the device. Cloud-hosted stacks invert this: assets, logs, and controller code live on a host or managed platform. Webots.cloud is unusually transparent in that its repository and docs spell out GitHub-based hosting and a `publish` flag controlling cloud publication behaviour. For Isaac Sim and other streamed approaches, privacy depends largely on how you operate the server and what provider policies apply. citeturn9search11turn9search4turn25view1turn21view1turn9search3


On **maturity**, MuJoCo and PhysX are highly mature engines, but the **MuJoCo web bindings** are still labelled **WIP**, while **PhysX-in-browser** is community-led. Rapier is modern and healthy, with official JS bindings and browser demos. Ammo.js remains useful and well known, but its upstream basis is older Bullet. Webots is one of the oldest robotics simulators in the set and webots.cloud is open-source. GzWeb remains functional but is burdened by the Gazebo Classic lifecycle. Isaac Sim is actively developed, but it belongs in the “remote workstation/cloud simulator” bucket, not the “drop a robot into a web page” bucket. citeturn14view1turn27view1turn27view0turn30view0turn1view3turn20search10turn31view0turn24view4


## Recommended ways to run G1 in-browser


### MuJoCo WASM with MJCF upload


This is the recommended path if you want to stay closest to the **official G1 MJCF**. MuJoCo’s web bindings are official, they support **MJCF and URDF**, and the test suite demonstrates loading XML after writing it into the in-memory filesystem. Because Unitree already publishes G1 MJCF and URDF, you can build a browser page that accepts `g1_*.xml` plus its mesh folder, writes them into the virtual FS, calls `mj_loadXML`, and steps the model in JavaScript. If your eventual goal is running a locomotion **ONNX** policy, this is also the approach with the cleanest path to preserving the original observation/action semantics. citeturn15view1turn14view1turn19view0turn25view0


**Required steps**

1. Add the official `@mujoco/mujoco` package to a small web app and serve the `.wasm` asset correctly.  

2. Build a file picker or drag-and-drop flow for the G1 MJCF and mesh assets.  

3. Write all XML/mesh files into the Emscripten FS, preserving relative paths.  

4. Load the model with `MjModel.mj_loadXML()`, create `MjData`, and render.  

5. Start with passive stepping or a fixed pose; add a controller loop next.  

6. If needed, integrate `onnxruntime-web` for policy inference and map observations/actions in JS. citeturn14view1turn15view1turn25view0turn25view1


**Pros**  

Direct use of G1 MJCF; best browser-native physics fidelity; easiest future path to matching MuJoCo-trained policies and contact behaviour. citeturn2search9turn15view1


**Cons**  

More engineering than a viewer; the web bindings are still marked WIP; no official turnkey upload app in the reviewed material. citeturn14view1


**Estimated time and complexity**  

A basic local uploader/viewer is realistically **one to two days** for an experienced web developer. Adding policy inference is usually **two to five days more**, depending mostly on whether observation normalisation and action scaling are already known. That second estimate is an inference from the stack shape, not a documented vendor promise. citeturn14view1turn25view1


**Useful repos/examples**  

Official MuJoCo JS bindings and demo app; `zalo/mujoco_wasm` as a focused demo suite; `mujoco-react` if you prefer a React/Three wrapper. citeturn14view1turn0search0turn0search14


```js

import loadMujoco from '@mujoco/mujoco';


const mujoco = await loadMujoco();


// xmlText comes from an uploaded G1 MJCF file

mujoco.FS.writeFile('/work/g1.xml', xmlText);


// write referenced mesh files too, preserving paths

// e.g. mujoco.FS.writeFile('/work/meshes/torso.STL', meshBytes)


const model = mujoco.MjModel.mj_loadXML('/work/g1.xml');

const data = new mujoco.MjData(model);


function tick() {

  mujoco.mj_step(model, data);

  requestAnimationFrame(tick);

}

tick();

```


### Three.js with URDFLoader and sliders


This is the recommended path if you want the **quickest visible browser result**. URDFLoader is purposely designed for loading URDF models into Three.js, offers a drag-and-drop component, handles package paths, and exposes direct joint control functions. Since Unitree publishes G1 URDF, this is the fastest way to get a G1 into a web page with orbit controls and 29 sliders. citeturn16view0turn16view1turn19view0


**Required steps**

1. Serve the G1 URDF and mesh files from a local dev server.  

2. Point URDFLoader at the correct package root.  

3. Add orbit controls and a simple slider GUI.  

4. Use `robot.setJointValue()` to pose the robot.  

5. Optionally export screenshots, saved poses, or a glTF approximation of the posed scene. citeturn16view0turn4search17


**Pros**  

Fastest route; easiest UX; ideal for debugging joint names, visual orientation, limits, and authoring poses. citeturn16view0


**Cons**  

No serious dynamics on its own; not suitable for balance, contacts, or locomotion research unless you bolt on a separate physics layer. citeturn16view0turn30view0


**Estimated time and complexity**  

Usually **two to four hours** for a basic page, and **half a day** for a polished slider-based viewer. citeturn16view0


**Useful repos/examples**  

The URDFLoader docs and demo pages are the relevant starting point. citeturn16view0turn20search19


```js

import URDFLoader from 'urdf-loader';


const loader = new URDFLoader();

loader.packages = {

  g1_description: '/assets/g1_description/'

};


loader.load('/assets/g1_description/urdf/g1_29dof.urdf', robot => {

  scene.add(robot);

  robot.setJointValue('left_hip_pitch_joint', 0.2);

  robot.setJointValue('right_hip_pitch_joint', -0.2);

});

```


### Three.js with Rapier for basic physics


This is the recommended middle path if you want **some real physics in-browser** but do not need MuJoCo-specific behaviour. Rapier has official browser bindings, joints, demos, and explicit support for web deployment. The usual pattern is to render with Three.js and step the world with Rapier. For robots, though, you still need a translation layer from G1’s URDF or MJCF into bodies, colliders, and joints. citeturn1view2turn30view0


**Required steps**

1. Choose a visual asset path: direct glTF, or URDF parsing for structure.  

2. Create rigid bodies and colliders for the torso, limbs, and feet.  

3. Add joint constraints matching the robot kinematics you care about.  

4. Sync Rapier transforms into Three.js meshes each frame.  

5. Add either keyboard control, pose targets, or ONNX inference through `onnxruntime-web`. citeturn1view2turn30view0turn25view0


**Pros**  

Modern, lightweight, browser-friendly, good performance features, straightforward to deploy. citeturn30view0


**Cons**  

You are effectively building your own robot simulator layer; no native MJCF/URDF robotics semantics. citeturn30view0turn1view2


**Estimated time and complexity**  

Expect roughly **half a day to one and a half days** for a toy articulated mock-up, and longer for a faithful G1 approximation. citeturn30view0


**Useful repos/examples**  

Rapier JS docs, official demos, and bindings repo. citeturn1view2turn20search4turn30view0


```js

import * as RAPIER from '@dimforge/rapier3d';


await RAPIER.init();

const world = new RAPIER.World({ x: 0, y: -9.81, z: 0 });


// ground

world.createCollider(RAPIER.ColliderDesc.cuboid(5, 0.1, 5));


// torso body

const torso = world.createRigidBody(

  RAPIER.RigidBodyDesc.dynamic().setTranslation(0, 1.0, 0)

);

world.createCollider(RAPIER.ColliderDesc.capsule(0.25, 0.12), torso);


function animate() {

  world.step();

  // sync torso.translation()/rotation() to a Three.js mesh here

  requestAnimationFrame(animate);

}

animate();

```


## Decision workflow and effort


The decision is less about “which engine is best” than about **which constraints matter most**: direct MJCF reuse, fastest time to first result, or some basic interactive physics.


```mermaid

flowchart TD

    A[Need G1 in a browser] --> B{Need real MJCF physics?}

    B -->|Yes| C[Use MuJoCo JS/WASM]

    B -->|No| D{Need only visual posing and joint UI?}

    D -->|Yes| E[Use Three.js + URDFLoader]

    D -->|No| F{Need light browser physics?}

    F -->|Yes| G[Use Three.js + Rapier]

    F -->|No| H{Need full desktop-grade simulator features?}

    H -->|Yes| I[Use cloud-hosted Isaac Sim or Webots.cloud]

    H -->|No| J[Stay browser-native and simplify scope]

```


That flow reflects the reviewed platform capabilities: **MuJoCo** is the strongest browser-native route for G1’s existing MJCF; **URDFLoader** is the fastest visual route; and **Rapier** is the most credible lightweight physics compromise. **Isaac Sim** and **Webots.cloud** remain valid when you accept cloud/server workflows instead of true browser-native execution. citeturn19view0turn14view1turn16view0turn30view0turn24view0turn21view1


```mermaid

gantt

    title Estimated effort for three G1 browser approaches

    dateFormat  YYYY-MM-DD

    axisFormat  %d %b


    section Fastest result

    Three.js + URDFLoader viewer           :a1, 2026-07-11, 0.5d


    section Middle ground

    Three.js + Rapier basic physics        :a2, after a1, 1d


    section Highest fidelity

    MuJoCo WASM MJCF uploader              :a3, 2026-07-11, 2d

    MuJoCo WASM + ONNX policy integration  :a4, after a3, 3d

```


The timeline is intentionally approximate. The biggest uncertainty is never rendering; it is always the **robot semantics layer**: file paths, inertias, controller mapping, and policy I/O definitions. That is why the “viewer first, physics second” sequence is often the safest delivery plan. citeturn15view1turn25view1


## Top links


- **MuJoCo JavaScript/WebAssembly bindings** citeturn14view1  

- **MuJoCo model loading and mesh format docs** citeturn2search9turn2search3  

- **Unitree G1 description package** citeturn19view0  

- **ONNX Runtime Web documentation** citeturn25view0turn25view1turn25view2  

- **URDFLoader docs and examples** citeturn16view0  

- **Rapier JavaScript getting started** citeturn1view2  

- **Ammo.js repository** citeturn1view3  

- **PhysX browser bindings and official PhysX SDK** citeturn27view0turn27view1  

- **Webots.cloud repository and docs** citeturn21view1  

- **Isaac Sim browser streaming and import docs** citeturn24view0turn24view1turn24view2  

- **Gazebo GzWeb overview and EOL notice** citeturn31view1turn31view0

Comments

Popular posts from this blog

go ahead baby, now on sale!!

Just Go For It, Baby by Red Sweet Pea