Compatibility

This page defines the compatibility contract between:

  • Play (this repo)

  • forge dist bundles (mujoco-wasm-forge outputs)

  • browsers (module Workers + WASM)

Browsers

Play requires:

  • ES modules in the main thread

  • module Workers (new Worker(url, { type: 'module' }))

  • WebAssembly

Most modern Chromium/Firefox/Safari versions satisfy these requirements.

Forge dist bundle requirements

Play expects a forge dist/<ver>/ directory that contains at least:

  • mujoco.js (ESM-capable loader)

  • mujoco.wasm

Recommended (optional):

  • version.json (optional; used for diagnostics in verbose/perf mode)

Viewer ABI extensions

Play validates that the loaded forge module exports a required viewer ABI set. If any export is missing, the Worker throws an error and reports the missing symbols.

The canonical list lives in worker/physics.worker.mjs:

        // Scene pipeline (mjv_updateScene -> packed SoA)
        '_mjwf_scene_update_and_pack',
        '_mjwf_scene_maxgeom_ptr',
        '_mjwf_scene_ngeom',
        '_mjwf_scene_geomorder_ptr',
        '_mjwf_scene_geoms_type_ptr',
        '_mjwf_scene_geoms_pos_ptr',
      '_mjwf_scene_geoms_mat_ptr',
      '_mjwf_scene_geoms_size_ptr',
      '_mjwf_scene_geoms_rgba_ptr',
      '_mjwf_scene_geoms_matid_ptr',
      '_mjwf_scene_geoms_dataid_ptr',
      '_mjwf_scene_geoms_objtype_ptr',
      '_mjwf_scene_geoms_objid_ptr',
      '_mjwf_scene_geoms_category_ptr',
      '_mjwf_scene_geoms_segid_ptr',
      '_mjwf_scene_geoms_transparent_ptr',
      // Viewer options (vopt pointers)
      '_mjwf_vopt_flags_ptr',
      '_mjwf_vopt_label_ptr',
      '_mjwf_vopt_frame_ptr',
      '_mjwf_vopt_flex_layer_ptr',
      '_mjwf_vopt_bvh_depth_ptr',
      '_mjwf_vopt_geomgroup_ptr',
      '_mjwf_vopt_sitegroup_ptr',
        '_mjwf_vopt_jointgroup_ptr',
        '_mjwf_vopt_tendongroup_ptr',
        '_mjwf_vopt_actuatorgroup_ptr',
        '_mjwf_vopt_flexgroup_ptr',
        '_mjwf_vopt_skingroup_ptr',
        // Viewer camera pointers (mjvCamera fields)
        '_mjwf_cam_type_ptr',
        '_mjwf_cam_lookat_ptr',
        '_mjwf_cam_distance_ptr',
        '_mjwf_cam_azimuth_ptr',
        '_mjwf_cam_elevation_ptr',
        '_mjwf_cam_fixedcamid_ptr',
        '_mjwf_cam_orthographic_ptr',
        '_mjwf_cam_trackbodyid_ptr',
        // Perturb pointers (mjvPerturb fields)
        '_mjwf_pert_select_ptr',
        '_mjwf_pert_active_ptr',
        '_mjwf_pert_active2_ptr',
        '_mjwf_pert_localpos_ptr',
        '_mjwf_pert_scale_ptr',
        '_mjwf_pert_flexselect_ptr',
        '_mjwf_pert_skinselect_ptr',
      // mjv helpers for perturb pipeline
      '_mjwf_mjv_updateCamera',
      '_mjwf_mjv_initPerturb',
      '_mjwf_mjv_movePerturb',
      '_mjwf_mjv_applyPerturbPose',
      '_mjwf_mjv_applyPerturbForce',
      // mjv helpers for selection
      '_mjwf_mjv_select',
      // mjv helpers for camera gestures
      '_mjwf_mjv_moveCamera',
    ];

Notes:

  • This is a viewer contract (scene packing, vopt/camera/perturb pointers, and mjv helpers).

  • If you build your own forge bundle, ensure viewer extensions are enabled.

Local dev vs hosted layouts

When forgeBase= is omitted, Play resolves a default forge base template and propagates it to the Worker:

  • single entry: /forge/dist/{ver}/

  • pthreads entry: /forge/dist/{ver}/pthreads/

The local dev server (tools/dev_server.py) mounts /forge/ to a sibling ../mujoco-wasm-forge checkout if present (otherwise it falls back to the Play repo root for local-only mirrors).

For explicit control (recommended for published demos), always pass forgeBase=... and pin it to an immutable forge commit.

Pthreads (SharedArrayBuffer)

If you use the pthreads entry (/pthreads/index.html):

  • the forge bundle must exist under dist/<ver>/pthreads/ (at least mujoco.js + mujoco.wasm), and

  • the page must be cross-origin isolated (crossOriginIsolated === true), which requires COOP/COEP headers.

Play hard-fails early if cross-origin isolation is missing.