mujoco-react 9.2.0 → 9.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- export { ScenarioLighting, SplatEnvironment, VisualScenarioEffects, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, getScenarioBackground, getScenarioCameraPosition, useSplatEnvironment, useVisualScenarioEffects, withSplatEnvironment } from './chunk-33CV6HSV.js';
1
+ import { withContacts, getContact } from './chunk-T3GVZJ4F.js';
2
+ export { RobotActuators, RobotBodies, RobotCameras, RobotGeoms, RobotJoints, RobotKeyframes, RobotResources, RobotSensors, RobotSites, ScenarioLighting, SplatEnvironment, SplatEnvironmentReadinessStatus, VisualScenarioEffects, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, getContact, getScenarioBackground, getScenarioCameraPosition, getSplatEnvironmentReadiness, registerRobotResources, useSplatEnvironment, useSplatSceneConfig, useVisualScenarioEffects, withSplatEnvironment } from './chunk-T3GVZJ4F.js';
2
3
  import loadMujoco from '@mujoco/mujoco';
3
4
  import defaultMujocoWasmUrl from '@mujoco/mujoco/mujoco.wasm?url';
4
5
  import { createContext, forwardRef, useEffect, useContext, useState, useRef, useCallback, useMemo, useLayoutEffect } from 'react';
@@ -104,80 +105,6 @@ function MujocoProvider({
104
105
  }
105
106
  );
106
107
  }
107
-
108
- // src/types.ts
109
- var runtimeRobotResources = {};
110
- var REGISTER_RESOURCE_KEYS = ["actuators", "sensors", "bodies", "joints", "sites", "geoms", "keyframes"];
111
- function createEmptyRuntimeResources() {
112
- return {
113
- actuators: {},
114
- sensors: {},
115
- bodies: {},
116
- joints: {},
117
- sites: {},
118
- geoms: {},
119
- keyframes: {}
120
- };
121
- }
122
- function registerRobotResources(resources) {
123
- for (const [robot, robotResources] of Object.entries(resources)) {
124
- const existing = runtimeRobotResources[robot] ?? createEmptyRuntimeResources();
125
- for (const key of REGISTER_RESOURCE_KEYS) {
126
- existing[key] = { ...existing[key], ...robotResources[key] ?? {} };
127
- }
128
- runtimeRobotResources[robot] = existing;
129
- }
130
- }
131
- function createResourceCategory(key) {
132
- return new Proxy({}, {
133
- get(_target, robot) {
134
- if (typeof robot !== "string") return void 0;
135
- return runtimeRobotResources[robot]?.[key] ?? {};
136
- },
137
- ownKeys() {
138
- return Reflect.ownKeys(runtimeRobotResources);
139
- },
140
- getOwnPropertyDescriptor(_target, robot) {
141
- if (typeof robot !== "string" || !(robot in runtimeRobotResources)) return void 0;
142
- return { enumerable: true, configurable: true };
143
- }
144
- });
145
- }
146
- var RobotResources = new Proxy(runtimeRobotResources, {
147
- get(target, robot) {
148
- if (typeof robot !== "string") return void 0;
149
- return target[robot] ?? createEmptyRuntimeResources();
150
- },
151
- ownKeys(target) {
152
- return Reflect.ownKeys(target);
153
- },
154
- getOwnPropertyDescriptor(target, robot) {
155
- if (typeof robot !== "string" || !(robot in target)) return void 0;
156
- return { enumerable: true, configurable: true };
157
- }
158
- });
159
- var RobotActuators = createResourceCategory("actuators");
160
- var RobotSensors = createResourceCategory("sensors");
161
- var RobotBodies = createResourceCategory("bodies");
162
- var RobotJoints = createResourceCategory("joints");
163
- var RobotSites = createResourceCategory("sites");
164
- var RobotGeoms = createResourceCategory("geoms");
165
- var RobotKeyframes = createResourceCategory("keyframes");
166
- function getContact(contacts, i) {
167
- try {
168
- return contacts.get(i);
169
- } catch {
170
- return void 0;
171
- }
172
- }
173
- function withContacts(data, read) {
174
- const contacts = data.contact;
175
- try {
176
- return read(contacts);
177
- } finally {
178
- contacts.delete?.();
179
- }
180
- }
181
108
  var CapsuleGeometry = class extends THREE12.BufferGeometry {
182
109
  parameters;
183
110
  constructor(radius = 1, length = 1, capSegments = 4, radialSegments = 8) {
@@ -480,6 +407,15 @@ function findSensorByName(mjModel, name) {
480
407
  }
481
408
  return -1;
482
409
  }
410
+ function findCameraByName(mjModel, name) {
411
+ const ncam = mjModel.ncam ?? 0;
412
+ const addresses = mjModel.name_camadr;
413
+ if (!addresses) return -1;
414
+ for (let i = 0; i < ncam; i++) {
415
+ if (getName(mjModel, addresses[i]) === name) return i;
416
+ }
417
+ return -1;
418
+ }
483
419
  function findTendonByName(mjModel, name) {
484
420
  for (let i = 0; i < (mjModel.ntendon ?? 0); i++) {
485
421
  if (getName(mjModel, mjModel.name_tendonadr[i]) === name) return i;
@@ -1439,17 +1375,32 @@ function createCaptureCamera(options, fallbackCamera, width, height) {
1439
1375
  applyCameraPose(camera, options, fallbackCamera);
1440
1376
  return camera;
1441
1377
  }
1442
- function readRenderTargetToCanvas(renderer, target, width, height) {
1443
- const pixels = new Uint8Array(width * height * 4);
1444
- renderer.readRenderTargetPixels(target, 0, 0, width, height, pixels);
1445
- const canvas = document.createElement("canvas");
1446
- canvas.width = width;
1447
- canvas.height = height;
1448
- const context = canvas.getContext("2d");
1449
- if (!context) {
1450
- throw new Error("Unable to create a 2D canvas for camera frame capture.");
1378
+ function getCaptureDimensions(renderer, options) {
1379
+ const width = Math.max(
1380
+ 1,
1381
+ Math.floor(options.width ?? renderer.domElement.width)
1382
+ );
1383
+ const height = Math.max(
1384
+ 1,
1385
+ Math.floor(options.height ?? renderer.domElement.height)
1386
+ );
1387
+ return { width, height };
1388
+ }
1389
+ function prepareCaptureCamera(camera, options, fallbackCamera, width, height) {
1390
+ if (options.camera) {
1391
+ camera.copy(options.camera);
1392
+ }
1393
+ if (camera instanceof THREE12.PerspectiveCamera) {
1394
+ camera.aspect = width / height;
1395
+ camera.fov = options.fov ?? camera.fov;
1396
+ camera.near = options.near ?? camera.near;
1397
+ camera.far = options.far ?? camera.far;
1398
+ camera.updateProjectionMatrix();
1451
1399
  }
1452
- const imageData = context.createImageData(width, height);
1400
+ applyCameraPose(camera, options, fallbackCamera);
1401
+ }
1402
+ function readRenderTargetToCanvas(renderer, target, canvas, context, pixels, imageData, width, height) {
1403
+ renderer.readRenderTargetPixels(target, 0, 0, width, height, pixels);
1453
1404
  const rowBytes = width * 4;
1454
1405
  for (let y = 0; y < height; y += 1) {
1455
1406
  const sourceStart = (height - y - 1) * rowBytes;
@@ -1462,28 +1413,133 @@ function readRenderTargetToCanvas(renderer, target, width, height) {
1462
1413
  context.putImageData(imageData, 0, 0);
1463
1414
  return canvas;
1464
1415
  }
1465
- function renderCameraFrameToCanvas(renderer, scene, fallbackCamera, options = {}) {
1466
- const width = Math.max(1, Math.floor(options.width ?? renderer.domElement.width));
1467
- const height = Math.max(1, Math.floor(options.height ?? renderer.domElement.height));
1416
+ function getCameraFrameCaptureSource(options) {
1417
+ if (options.source) return options.source;
1418
+ if (options.cameraName) {
1419
+ return { kind: "mujoco-camera", cameraName: options.cameraName };
1420
+ }
1421
+ if (options.siteName) {
1422
+ return { kind: "mujoco-site", siteName: options.siteName };
1423
+ }
1424
+ if (options.bodyName) {
1425
+ return { kind: "mujoco-body", bodyName: options.bodyName };
1426
+ }
1427
+ if (options.camera) return { kind: "custom-camera" };
1428
+ if (options.position || options.lookAt || options.quaternion) {
1429
+ return { kind: "explicit-pose" };
1430
+ }
1431
+ return { kind: "fallback-camera" };
1432
+ }
1433
+ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, options = {}) {
1434
+ const { width, height } = getCaptureDimensions(renderer, options);
1468
1435
  const camera = createCaptureCamera(options, fallbackCamera, width, height);
1469
1436
  const target = new THREE12.WebGLRenderTarget(width, height, {
1470
1437
  format: THREE12.RGBAFormat,
1471
1438
  type: THREE12.UnsignedByteType
1472
1439
  });
1473
- const previousTarget = renderer.getRenderTarget();
1474
- const previousXrEnabled = renderer.xr.enabled;
1475
- scene.updateMatrixWorld(true);
1440
+ const canvas = document.createElement("canvas");
1441
+ canvas.width = width;
1442
+ canvas.height = height;
1443
+ const context = canvas.getContext("2d");
1444
+ if (!context) {
1445
+ target.dispose();
1446
+ throw new Error("Unable to create a 2D canvas for camera frame capture.");
1447
+ }
1448
+ const drawContext = context;
1449
+ const pixels = new Uint8Array(width * height * 4);
1450
+ const imageData = drawContext.createImageData(width, height);
1451
+ function capture(nextOptions = {}) {
1452
+ const captureOptions = { ...options, ...nextOptions };
1453
+ const nextDimensions = getCaptureDimensions(renderer, captureOptions);
1454
+ if (nextDimensions.width !== width || nextDimensions.height !== height) {
1455
+ throw new Error(
1456
+ "Camera frame capture sessions require stable width and height."
1457
+ );
1458
+ }
1459
+ prepareCaptureCamera(
1460
+ camera,
1461
+ captureOptions,
1462
+ fallbackCamera,
1463
+ width,
1464
+ height
1465
+ );
1466
+ const previousTarget = renderer.getRenderTarget();
1467
+ const previousXrEnabled = renderer.xr.enabled;
1468
+ scene.updateMatrixWorld(true);
1469
+ try {
1470
+ renderer.xr.enabled = false;
1471
+ renderer.setRenderTarget(target);
1472
+ renderer.clear();
1473
+ renderer.render(scene, camera);
1474
+ readRenderTargetToCanvas(
1475
+ renderer,
1476
+ target,
1477
+ canvas,
1478
+ drawContext,
1479
+ pixels,
1480
+ imageData,
1481
+ width,
1482
+ height
1483
+ );
1484
+ return {
1485
+ canvas,
1486
+ camera,
1487
+ width,
1488
+ height,
1489
+ source: getCameraFrameCaptureSource(captureOptions)
1490
+ };
1491
+ } finally {
1492
+ renderer.setRenderTarget(previousTarget);
1493
+ renderer.xr.enabled = previousXrEnabled;
1494
+ }
1495
+ }
1496
+ return {
1497
+ width,
1498
+ height,
1499
+ capture,
1500
+ captureDataUrl(nextOptions = {}) {
1501
+ const type = nextOptions.type ?? options.type ?? "image/png";
1502
+ const result = capture(nextOptions);
1503
+ return {
1504
+ ...result,
1505
+ dataUrl: result.canvas.toDataURL(
1506
+ type,
1507
+ nextOptions.quality ?? options.quality
1508
+ ),
1509
+ type
1510
+ };
1511
+ },
1512
+ async captureBlob(nextOptions = {}) {
1513
+ const type = nextOptions.type ?? options.type ?? "image/png";
1514
+ const result = capture(nextOptions);
1515
+ const blob = await new Promise((resolve, reject) => {
1516
+ result.canvas.toBlob(
1517
+ (nextBlob) => {
1518
+ if (nextBlob) resolve(nextBlob);
1519
+ else reject(new Error("Camera frame capture did not produce a Blob."));
1520
+ },
1521
+ type,
1522
+ nextOptions.quality ?? options.quality
1523
+ );
1524
+ });
1525
+ return { ...result, blob, type };
1526
+ },
1527
+ dispose() {
1528
+ target.dispose();
1529
+ }
1530
+ };
1531
+ }
1532
+ function renderCameraFrameToCanvas(renderer, scene, fallbackCamera, options = {}) {
1533
+ const session = createCameraFrameCaptureSession(
1534
+ renderer,
1535
+ scene,
1536
+ fallbackCamera,
1537
+ options
1538
+ );
1476
1539
  try {
1477
- renderer.xr.enabled = false;
1478
- renderer.setRenderTarget(target);
1479
- renderer.clear();
1480
- renderer.render(scene, camera);
1481
- const canvas = readRenderTargetToCanvas(renderer, target, width, height);
1482
- return { canvas, camera, width, height };
1540
+ return session.capture();
1483
1541
  } finally {
1484
- renderer.setRenderTarget(previousTarget);
1485
- renderer.xr.enabled = previousXrEnabled;
1486
- target.dispose();
1542
+ session.dispose();
1487
1543
  }
1488
1544
  }
1489
1545
  async function captureCameraFrame(renderer, scene, fallbackCamera, options = {}) {
@@ -1520,6 +1576,174 @@ async function captureCameraFrameBlob(renderer, scene, fallbackCamera, options =
1520
1576
  });
1521
1577
  return { ...result, blob, type };
1522
1578
  }
1579
+
1580
+ // src/rendering/cameraFrameSource.ts
1581
+ var MountedCameraFrameSequenceReadinessStatus = {
1582
+ Ready: "ready",
1583
+ Partial: "partial",
1584
+ Missing: "missing"
1585
+ };
1586
+ function getResourceName(resource) {
1587
+ if (!resource) return null;
1588
+ return typeof resource === "string" ? resource : resource.name ?? null;
1589
+ }
1590
+ function createNameSet(resources) {
1591
+ return new Set(
1592
+ (resources ?? []).map((resource) => getResourceName(resource)).filter((name) => Boolean(name))
1593
+ );
1594
+ }
1595
+ function normalizeAliasCandidates(value) {
1596
+ if (!value) return [];
1597
+ return Array.isArray(value) ? value : [value];
1598
+ }
1599
+ function countMountedSelectors(selector) {
1600
+ return Number(Boolean(selector.cameraName)) + Number(Boolean(selector.siteName)) + Number(Boolean(selector.bodyName));
1601
+ }
1602
+ function getMountedCameraFrameCaptureSource(selector) {
1603
+ if (countMountedSelectors(selector) !== 1) return null;
1604
+ if (selector.cameraName) {
1605
+ return { kind: "mujoco-camera", cameraName: selector.cameraName };
1606
+ }
1607
+ if (selector.siteName) {
1608
+ return { kind: "mujoco-site", siteName: selector.siteName };
1609
+ }
1610
+ if (selector.bodyName) {
1611
+ return { kind: "mujoco-body", bodyName: selector.bodyName };
1612
+ }
1613
+ return null;
1614
+ }
1615
+ function isMountedCameraFrameCaptureSource(source) {
1616
+ return source.kind === "mujoco-camera" || source.kind === "mujoco-site" || source.kind === "mujoco-body";
1617
+ }
1618
+ function getCameraFrameCaptureSourceTarget(source) {
1619
+ if (source.kind === "mujoco-camera") return source.cameraName;
1620
+ if (source.kind === "mujoco-site") return source.siteName;
1621
+ if (source.kind === "mujoco-body") return source.bodyName;
1622
+ if (source.kind === "custom-camera") return "custom camera";
1623
+ if (source.kind === "explicit-pose") return "explicit pose";
1624
+ return "fallback camera";
1625
+ }
1626
+ function isSelectorMounted(selector, cameraNames, siteNames, bodyNames) {
1627
+ if (countMountedSelectors(selector) !== 1) return false;
1628
+ return (selector.cameraName ? cameraNames.has(selector.cameraName) : false) || (selector.siteName ? siteNames.has(selector.siteName) : false) || (selector.bodyName ? bodyNames.has(selector.bodyName) : false);
1629
+ }
1630
+ function resolveMountedCameraFrameSource(key, options) {
1631
+ const cameraNames = createNameSet(options.cameras);
1632
+ const siteNames = createNameSet(options.sites);
1633
+ const bodyNames = createNameSet(options.bodies);
1634
+ const directCandidates = [
1635
+ { cameraName: key },
1636
+ { siteName: key },
1637
+ { bodyName: key }
1638
+ ];
1639
+ const aliasCandidates = normalizeAliasCandidates(options.aliases?.[key]);
1640
+ const candidates = [...directCandidates, ...aliasCandidates];
1641
+ for (const selector of candidates) {
1642
+ if (!isSelectorMounted(selector, cameraNames, siteNames, bodyNames)) {
1643
+ continue;
1644
+ }
1645
+ const source = getMountedCameraFrameCaptureSource(selector);
1646
+ if (!source) continue;
1647
+ return { key, selector, source };
1648
+ }
1649
+ if (options.allowAliasFallback) {
1650
+ for (const selector of aliasCandidates) {
1651
+ const source = getMountedCameraFrameCaptureSource(selector);
1652
+ if (!source) continue;
1653
+ return { key, selector, source };
1654
+ }
1655
+ }
1656
+ return null;
1657
+ }
1658
+ function createMountedCameraFrameSequencePlan(cameraKeys, options) {
1659
+ const cameras = [];
1660
+ const resolved = {};
1661
+ const missingKeys = [];
1662
+ for (const key of cameraKeys) {
1663
+ const mountedSource = resolveMountedCameraFrameSource(key, options);
1664
+ if (!mountedSource) {
1665
+ missingKeys.push(key);
1666
+ continue;
1667
+ }
1668
+ resolved[key] = mountedSource;
1669
+ cameras.push({
1670
+ key,
1671
+ ...options.defaults,
1672
+ ...options.cameraOptions?.[key],
1673
+ ...mountedSource.selector,
1674
+ source: mountedSource.source
1675
+ });
1676
+ }
1677
+ if (options.requireAll && missingKeys.length > 0) {
1678
+ throw new Error(
1679
+ `Unable to resolve mounted MuJoCo camera source${missingKeys.length === 1 ? "" : "s"} for ${missingKeys.join(", ")}.`
1680
+ );
1681
+ }
1682
+ return {
1683
+ cameraKeys: [...cameraKeys],
1684
+ cameras,
1685
+ resolved,
1686
+ missingKeys
1687
+ };
1688
+ }
1689
+ function createMountedCameraFrameSequenceReadiness(plan) {
1690
+ const cameras = {};
1691
+ const resolvedKeys = plan.cameraKeys.filter((key) => Boolean(plan.resolved[key]));
1692
+ for (const key of plan.cameraKeys) {
1693
+ const resolved = plan.resolved[key];
1694
+ cameras[key] = resolved ? {
1695
+ key,
1696
+ ready: true,
1697
+ selector: resolved.selector,
1698
+ source: resolved.source,
1699
+ message: `Camera stream "${key}" resolves to ${resolved.source.kind}:${getCameraFrameCaptureSourceTarget(resolved.source)}.`
1700
+ } : {
1701
+ key,
1702
+ ready: false,
1703
+ message: `Camera stream "${key}" does not resolve to a mounted MuJoCo camera, site, or body.`
1704
+ };
1705
+ }
1706
+ const missingKeys = [...plan.missingKeys];
1707
+ const ready = missingKeys.length === 0;
1708
+ const status = ready ? MountedCameraFrameSequenceReadinessStatus.Ready : resolvedKeys.length > 0 ? MountedCameraFrameSequenceReadinessStatus.Partial : MountedCameraFrameSequenceReadinessStatus.Missing;
1709
+ return {
1710
+ ready,
1711
+ status,
1712
+ cameraKeys: [...plan.cameraKeys],
1713
+ resolvedKeys,
1714
+ missingKeys,
1715
+ cameras,
1716
+ message: ready ? `All ${plan.cameraKeys.length} requested camera stream${plan.cameraKeys.length === 1 ? "" : "s"} resolve to mounted MuJoCo sources.` : `Missing mounted MuJoCo source${missingKeys.length === 1 ? "" : "s"} for ${missingKeys.join(", ")}.`
1717
+ };
1718
+ }
1719
+ function createMountedCameraFrameSequencePlanFromApi(api, cameraKeys, options = {}) {
1720
+ return createMountedCameraFrameSequencePlan(cameraKeys, {
1721
+ ...options,
1722
+ cameras: api.getCameras(),
1723
+ sites: api.getSites(),
1724
+ bodies: api.getBodies()
1725
+ });
1726
+ }
1727
+ async function recordMountedCameraFrameSequence(api, options) {
1728
+ const { cameraKeys, ...restOptions } = options;
1729
+ const requireAll = restOptions.requireAll ?? restOptions.requireMountedSources ?? true;
1730
+ const plan = createMountedCameraFrameSequencePlanFromApi(
1731
+ api,
1732
+ cameraKeys,
1733
+ { ...restOptions, requireAll }
1734
+ );
1735
+ const readiness = createMountedCameraFrameSequenceReadiness(plan);
1736
+ const result = await api.recordCameraSequence({
1737
+ ...restOptions,
1738
+ cameras: plan.cameras,
1739
+ requireMountedSources: restOptions.requireMountedSources ?? true
1740
+ });
1741
+ return {
1742
+ ...result,
1743
+ plan,
1744
+ readiness
1745
+ };
1746
+ }
1523
1747
  var JOINT_TYPE_NAMES2 = ["free", "ball", "slide", "hinge"];
1524
1748
  var GEOM_TYPE_NAMES = ["plane", "hfield", "sphere", "capsule", "ellipsoid", "cylinder", "box", "mesh"];
1525
1749
  var SENSOR_TYPE_NAMES = {
@@ -1602,6 +1826,72 @@ function waitForNextAnimationFrame2() {
1602
1826
  requestAnimationFrame(() => resolve());
1603
1827
  });
1604
1828
  }
1829
+ function throwIfCameraSequenceAborted(signal) {
1830
+ if (!signal?.aborted) return;
1831
+ if (typeof signal.reason === "object" && signal.reason instanceof Error) {
1832
+ throw signal.reason;
1833
+ }
1834
+ throw new DOMException("Camera sequence recording was aborted.", "AbortError");
1835
+ }
1836
+ function vector3FromArray(values, offset) {
1837
+ return [values[offset], values[offset + 1], values[offset + 2]];
1838
+ }
1839
+ function quaternionFromArray(values, offset) {
1840
+ return [
1841
+ values[offset],
1842
+ values[offset + 1],
1843
+ values[offset + 2],
1844
+ values[offset + 3]
1845
+ ];
1846
+ }
1847
+ function quaternionFromXmat(values, offset) {
1848
+ const matrix = new THREE12.Matrix4();
1849
+ matrix.set(
1850
+ values[offset],
1851
+ values[offset + 1],
1852
+ values[offset + 2],
1853
+ 0,
1854
+ values[offset + 3],
1855
+ values[offset + 4],
1856
+ values[offset + 5],
1857
+ 0,
1858
+ values[offset + 6],
1859
+ values[offset + 7],
1860
+ values[offset + 8],
1861
+ 0,
1862
+ 0,
1863
+ 0,
1864
+ 0,
1865
+ 1
1866
+ );
1867
+ const quaternion = new THREE12.Quaternion().setFromRotationMatrix(matrix);
1868
+ return [quaternion.x, quaternion.y, quaternion.z, quaternion.w];
1869
+ }
1870
+ function omitResolvedCameraSelectors(options) {
1871
+ const { cameraName, siteName, bodyName, ...rest } = options;
1872
+ return rest;
1873
+ }
1874
+ function countMountedCameraSelectors(options) {
1875
+ return Number(Boolean(options.cameraName)) + Number(Boolean(options.siteName)) + Number(Boolean(options.bodyName));
1876
+ }
1877
+ function assertMatchingMountedCameraSource(key, requested, source) {
1878
+ const selectorCount = countMountedCameraSelectors(requested);
1879
+ if (selectorCount !== 1) {
1880
+ throw new Error(
1881
+ `Camera sequence stream "${key}" must provide exactly one mounted MuJoCo cameraName, siteName, or bodyName selector.`
1882
+ );
1883
+ }
1884
+ if (!isMountedCameraFrameCaptureSource(source)) {
1885
+ throw new Error(
1886
+ `Camera sequence stream "${key}" resolved to ${source.kind}; use a MuJoCo-mounted camera, site, or body selector for sequence recording.`
1887
+ );
1888
+ }
1889
+ if (requested.cameraName && (source.kind !== "mujoco-camera" || source.cameraName !== requested.cameraName) || requested.siteName && (source.kind !== "mujoco-site" || source.siteName !== requested.siteName) || requested.bodyName && (source.kind !== "mujoco-body" || source.bodyName !== requested.bodyName)) {
1890
+ throw new Error(
1891
+ `Camera sequence stream "${key}" resolved to ${source.kind}:${getCameraFrameCaptureSourceTarget(source)} instead of the requested mounted selector.`
1892
+ );
1893
+ }
1894
+ }
1605
1895
  var MujocoSimContext = createContext(null);
1606
1896
  function useMujocoContext() {
1607
1897
  const ctx = useContext(MujocoSimContext);
@@ -1721,6 +2011,9 @@ function MujocoSimProvider({
1721
2011
  useEffect(() => {
1722
2012
  configRef.current = config;
1723
2013
  }, [config]);
2014
+ useEffect(() => {
2015
+ mujocoRef.current = mujoco;
2016
+ }, [mujoco]);
1724
2017
  useEffect(() => {
1725
2018
  pausedRef.current = paused ?? false;
1726
2019
  }, [paused]);
@@ -1768,6 +2061,7 @@ function MujocoSimProvider({
1768
2061
  result.mjData.delete();
1769
2062
  return;
1770
2063
  }
2064
+ mujocoRef.current = mujoco;
1771
2065
  mjModelRef.current = result.mjModel;
1772
2066
  mjDataRef.current = result.mjData;
1773
2067
  physicsAccumulatorRef.current = 0;
@@ -1833,7 +2127,7 @@ function MujocoSimProvider({
1833
2127
  if (!interpolateRef.current) {
1834
2128
  if (stepsToRunRef.current > 0) {
1835
2129
  for (let s = 0; s < stepsToRunRef.current; s++) {
1836
- mujoco.mj_step(model, data);
2130
+ mujocoRef.current.mj_step(model, data);
1837
2131
  }
1838
2132
  stepsToRunRef.current = 0;
1839
2133
  } else {
@@ -1842,7 +2136,7 @@ function MujocoSimProvider({
1842
2136
  const frameTime = clampedDelta * speedRef.current;
1843
2137
  while (data.time - startSimTime < frameTime) {
1844
2138
  for (let s = 0; s < numSubsteps; s++) {
1845
- mujoco.mj_step(model, data);
2139
+ mujocoRef.current.mj_step(model, data);
1846
2140
  }
1847
2141
  }
1848
2142
  }
@@ -1850,7 +2144,7 @@ function MujocoSimProvider({
1850
2144
  ensureInterpolationBuffers(model);
1851
2145
  copyBodyPose(data, interpolationStateRef.current.previousXpos, interpolationStateRef.current.previousXquat);
1852
2146
  for (let s = 0; s < stepsToRunRef.current; s++) {
1853
- mujoco.mj_step(model, data);
2147
+ mujocoRef.current.mj_step(model, data);
1854
2148
  }
1855
2149
  copyBodyPose(data, interpolationStateRef.current.currentXpos, interpolationStateRef.current.currentXquat);
1856
2150
  interpolationStateRef.current.alpha = 1;
@@ -1865,7 +2159,7 @@ function MujocoSimProvider({
1865
2159
  while (physicsAccumulatorRef.current >= stepDt) {
1866
2160
  copyBodyPose(data, interpolationStateRef.current.previousXpos, interpolationStateRef.current.previousXquat);
1867
2161
  for (let s = 0; s < numSubsteps; s++) {
1868
- mujoco.mj_step(model, data);
2162
+ mujocoRef.current.mj_step(model, data);
1869
2163
  }
1870
2164
  copyBodyPose(data, interpolationStateRef.current.currentXpos, interpolationStateRef.current.currentXquat);
1871
2165
  physicsAccumulatorRef.current -= stepDt;
@@ -1904,7 +2198,7 @@ function MujocoSimProvider({
1904
2198
  const model = mjModelRef.current;
1905
2199
  const data = mjDataRef.current;
1906
2200
  if (!model || !data) return;
1907
- mujoco.mj_resetData(model, data);
2201
+ mujocoRef.current.mj_resetData(model, data);
1908
2202
  const homeJoints = configRef.current.homeJoints;
1909
2203
  if (homeJoints) {
1910
2204
  const homeCount = Math.min(homeJoints.length, model.nu);
@@ -1917,7 +2211,7 @@ function MujocoSimProvider({
1917
2211
  }
1918
2212
  }
1919
2213
  configRef.current.onReset?.({ model, data });
1920
- mujoco.mj_forward(model, data);
2214
+ mujocoRef.current.mj_forward(model, data);
1921
2215
  for (const cb of resetCallbacks.current) {
1922
2216
  cb();
1923
2217
  }
@@ -1935,7 +2229,7 @@ function MujocoSimProvider({
1935
2229
  const step = useCallback((n = 1) => {
1936
2230
  stepsToRunRef.current = n;
1937
2231
  }, []);
1938
- const stepImmediately = useCallback((steps = 1) => {
2232
+ useCallback((steps = 1) => {
1939
2233
  const model = mjModelRef.current;
1940
2234
  const data = mjDataRef.current;
1941
2235
  if (!model || !data) return false;
@@ -1946,7 +2240,7 @@ function MujocoSimProvider({
1946
2240
  for (const cb of beforeStepCallbacks.current) {
1947
2241
  cb({ model, data });
1948
2242
  }
1949
- mujoco.mj_step(model, data);
2243
+ mujocoRef.current.mj_step(model, data);
1950
2244
  for (const cb of afterStepCallbacks.current) {
1951
2245
  cb({ model, data });
1952
2246
  }
@@ -1984,7 +2278,7 @@ function MujocoSimProvider({
1984
2278
  data.ctrl.set(snapshot.ctrl);
1985
2279
  if (snapshot.act.length > 0) data.act.set(snapshot.act);
1986
2280
  data.qfrc_applied.set(snapshot.qfrc_applied);
1987
- mujoco.mj_forward(model, data);
2281
+ mujocoRef.current.mj_forward(model, data);
1988
2282
  }, [mujoco]);
1989
2283
  const setQpos = useCallback((values) => {
1990
2284
  const model = mjModelRef.current;
@@ -1992,7 +2286,7 @@ function MujocoSimProvider({
1992
2286
  if (!model || !data) return;
1993
2287
  const arr = values instanceof Float64Array ? values : new Float64Array(values);
1994
2288
  data.qpos.set(arr.subarray(0, Math.min(arr.length, model.nq)));
1995
- mujoco.mj_forward(model, data);
2289
+ mujocoRef.current.mj_forward(model, data);
1996
2290
  }, [mujoco]);
1997
2291
  const setQvel = useCallback((values) => {
1998
2292
  const data = mjDataRef.current;
@@ -2227,6 +2521,88 @@ function MujocoSimProvider({
2227
2521
  }
2228
2522
  return result;
2229
2523
  }, []);
2524
+ const getCameras = useCallback(() => {
2525
+ const model = mjModelRef.current;
2526
+ if (!model) return [];
2527
+ const ncam = model.ncam ?? 0;
2528
+ const nameAddresses = model.name_camadr;
2529
+ if (!ncam || !nameAddresses) return [];
2530
+ const result = [];
2531
+ for (let i = 0; i < ncam; i += 1) {
2532
+ const posOffset = i * 3;
2533
+ const quatOffset = i * 4;
2534
+ result.push({
2535
+ id: i,
2536
+ name: getName(model, nameAddresses[i]),
2537
+ bodyId: model.cam_bodyid?.[i] ?? -1,
2538
+ fov: model.cam_fovy?.[i] ?? null,
2539
+ position: model.cam_pos ? vector3FromArray(model.cam_pos, posOffset) : null,
2540
+ quaternion: model.cam_quat ? quaternionFromArray(model.cam_quat, quatOffset) : null
2541
+ });
2542
+ }
2543
+ return result;
2544
+ }, []);
2545
+ const resolveCameraCaptureOptions = useCallback(
2546
+ (options = {}) => {
2547
+ const model = mjModelRef.current;
2548
+ const data = mjDataRef.current;
2549
+ if (!model || !data) {
2550
+ return options;
2551
+ }
2552
+ const baseOptions = omitResolvedCameraSelectors(options);
2553
+ if (options.cameraName) {
2554
+ const cameraId = findCameraByName(model, options.cameraName);
2555
+ if (cameraId < 0) {
2556
+ throw new Error(`MuJoCo camera "${options.cameraName}" was not found.`);
2557
+ }
2558
+ const position = data.cam_xpos ? vector3FromArray(data.cam_xpos, cameraId * 3) : model.cam_pos ? vector3FromArray(model.cam_pos, cameraId * 3) : void 0;
2559
+ const quaternion = data.cam_xmat ? quaternionFromXmat(data.cam_xmat, cameraId * 9) : model.cam_quat ? quaternionFromArray(model.cam_quat, cameraId * 4) : void 0;
2560
+ if (!position || !quaternion) {
2561
+ throw new Error(
2562
+ `MuJoCo camera "${options.cameraName}" does not expose a capture pose.`
2563
+ );
2564
+ }
2565
+ return {
2566
+ ...baseOptions,
2567
+ position,
2568
+ quaternion,
2569
+ fov: options.fov ?? model.cam_fovy?.[cameraId],
2570
+ source: { kind: "mujoco-camera", cameraName: options.cameraName }
2571
+ };
2572
+ }
2573
+ if (options.siteName) {
2574
+ const siteId = findSiteByName(model, options.siteName);
2575
+ if (siteId < 0) {
2576
+ throw new Error(`MuJoCo site "${options.siteName}" was not found.`);
2577
+ }
2578
+ return {
2579
+ ...baseOptions,
2580
+ position: vector3FromArray(data.site_xpos, siteId * 3),
2581
+ quaternion: quaternionFromXmat(data.site_xmat, siteId * 9),
2582
+ source: { kind: "mujoco-site", siteName: options.siteName }
2583
+ };
2584
+ }
2585
+ if (options.bodyName) {
2586
+ const bodyId = findBodyByName(model, options.bodyName);
2587
+ if (bodyId < 0) {
2588
+ throw new Error(`MuJoCo body "${options.bodyName}" was not found.`);
2589
+ }
2590
+ if (!data.xmat) {
2591
+ throw new Error(
2592
+ `MuJoCo body "${options.bodyName}" does not expose world orientation data.`
2593
+ );
2594
+ }
2595
+ return {
2596
+ ...baseOptions,
2597
+ position: vector3FromArray(data.xpos, bodyId * 3),
2598
+ quaternion: quaternionFromXmat(data.xmat, bodyId * 9),
2599
+ source: { kind: "mujoco-body", bodyName: options.bodyName }
2600
+ };
2601
+ }
2602
+ return options;
2603
+ },
2604
+ []
2605
+ );
2230
2606
  const getModelOption = useCallback(() => {
2231
2607
  const model = mjModelRef.current;
2232
2608
  if (!model?.opt) return { timestep: 2e-3, gravity: [0, 0, -9.81], integrator: 0 };
@@ -2303,7 +2679,7 @@ function MujocoSimProvider({
2303
2679
  const qvelOffset = keyId * model.nv;
2304
2680
  for (let i = 0; i < model.nv; i++) data.qvel[i] = model.key_qvel[qvelOffset + i];
2305
2681
  }
2306
- mujoco.mj_forward(model, data);
2682
+ mujocoRef.current.mj_forward(model, data);
2307
2683
  for (const cb of resetCallbacks.current) {
2308
2684
  cb();
2309
2685
  }
@@ -2414,67 +2790,187 @@ function MujocoSimProvider({
2414
2790
  );
2415
2791
  const captureCameraFrameApi = useCallback(
2416
2792
  (options = {}) => {
2417
- return captureCameraFrame(gl, scene, camera, options);
2793
+ return captureCameraFrame(
2794
+ gl,
2795
+ scene,
2796
+ camera,
2797
+ resolveCameraCaptureOptions(options)
2798
+ );
2418
2799
  },
2419
- [camera, gl, scene]
2800
+ [camera, gl, resolveCameraCaptureOptions, scene]
2420
2801
  );
2421
2802
  const captureCameraFrameBlobApi = useCallback(
2422
2803
  (options = {}) => {
2423
- return captureCameraFrameBlob(gl, scene, camera, options);
2804
+ return captureCameraFrameBlob(
2805
+ gl,
2806
+ scene,
2807
+ camera,
2808
+ resolveCameraCaptureOptions(options)
2809
+ );
2424
2810
  },
2425
- [camera, gl, scene]
2811
+ [camera, gl, resolveCameraCaptureOptions, scene]
2426
2812
  );
2427
2813
  const recordCameraSequenceApi = useCallback(
2428
2814
  async (options) => {
2429
2815
  const frameCount = Math.max(0, Math.floor(options.frames));
2430
- const stepsPerFrame = Math.max(1, Math.floor(options.stepsPerFrame ?? 1));
2816
+ const stepsPerFrame = Math.max(0, Math.floor(options.stepsPerFrame ?? 1));
2431
2817
  const cameras = options.cameras;
2432
2818
  const frames = [];
2819
+ const cameraSummaries = {};
2433
2820
  const wasPaused = pausedRef.current;
2821
+ const retainFrames = options.retainFrames ?? true;
2822
+ const requireMountedSources = options.requireMountedSources ?? true;
2823
+ let recordedFrameCount = 0;
2824
+ async function stepCameraSequence(frameIndex, steps) {
2825
+ const model = mjModelRef.current;
2826
+ const data = mjDataRef.current;
2827
+ if (!model || !data) {
2828
+ throw new Error("MuJoCo scene is not ready for camera sequence stepping.");
2829
+ }
2830
+ for (let stepIndex = 0; stepIndex < steps; stepIndex += 1) {
2831
+ for (let i = 0; i < model.nv; i += 1) {
2832
+ data.qfrc_applied[i] = 0;
2833
+ }
2834
+ await options.onBeforeStep?.({
2835
+ frameIndex,
2836
+ stepIndex,
2837
+ time: data.time,
2838
+ model,
2839
+ data
2840
+ });
2841
+ for (const cb of beforeStepCallbacks.current) {
2842
+ cb({ model, data });
2843
+ }
2844
+ mujocoRef.current.mj_step(model, data);
2845
+ for (const cb of afterStepCallbacks.current) {
2846
+ cb({ model, data });
2847
+ }
2848
+ onStepRef.current?.({ time: data.time, model, data });
2849
+ await options.onAfterStep?.({
2850
+ frameIndex,
2851
+ stepIndex,
2852
+ time: data.time,
2853
+ model,
2854
+ data
2855
+ });
2856
+ }
2857
+ physicsAccumulatorRef.current = 0;
2858
+ interpolationStateRef.current.valid = false;
2859
+ }
2434
2860
  if (frameCount === 0 || cameras.length === 0) {
2435
2861
  return {
2436
2862
  frames,
2437
2863
  cameraKeys: cameras.map((sequenceCamera) => sequenceCamera.key),
2864
+ cameraSummaries,
2438
2865
  frameCount: 0
2439
2866
  };
2440
2867
  }
2868
+ throwIfCameraSequenceAborted(options.signal);
2869
+ for (let attempt = 0; attempt < 30; attempt += 1) {
2870
+ if (mjModelRef.current && mjDataRef.current) break;
2871
+ await waitForNextAnimationFrame2();
2872
+ throwIfCameraSequenceAborted(options.signal);
2873
+ }
2874
+ if (!mjModelRef.current || !mjDataRef.current) {
2875
+ throw new Error("MuJoCo scene is not ready for camera sequence recording.");
2876
+ }
2877
+ const captureSessions = cameras.map((sequenceCamera) => {
2878
+ const { key, ...captureOptions } = sequenceCamera;
2879
+ const initialCaptureOptions = resolveCameraCaptureOptions(captureOptions);
2880
+ const mountedSource = initialCaptureOptions.source;
2881
+ if (requireMountedSources) {
2882
+ assertMatchingMountedCameraSource(
2883
+ key,
2884
+ captureOptions,
2885
+ mountedSource ?? { kind: "fallback-camera" }
2886
+ );
2887
+ }
2888
+ return {
2889
+ key,
2890
+ captureOptions,
2891
+ mountedSource,
2892
+ session: createCameraFrameCaptureSession(
2893
+ gl,
2894
+ scene,
2895
+ camera,
2896
+ initialCaptureOptions
2897
+ )
2898
+ };
2899
+ });
2441
2900
  try {
2442
2901
  pausedRef.current = true;
2443
2902
  stepsToRunRef.current = 0;
2444
2903
  if (options.reset) reset();
2445
2904
  for (let frameIndex = 0; frameIndex < frameCount; frameIndex += 1) {
2446
- if (frameIndex > 0 || options.captureInitialFrame === false) {
2447
- stepImmediately(stepsPerFrame);
2905
+ throwIfCameraSequenceAborted(options.signal);
2906
+ if (stepsPerFrame > 0 && (frameIndex > 0 || options.captureInitialFrame === false)) {
2907
+ await stepCameraSequence(frameIndex, stepsPerFrame);
2448
2908
  }
2449
2909
  await waitForNextAnimationFrame2();
2910
+ throwIfCameraSequenceAborted(options.signal);
2911
+ const model = mjModelRef.current;
2912
+ const data = mjDataRef.current;
2913
+ if (!model || !data) {
2914
+ throw new Error("MuJoCo scene is not ready for camera sequence sampling.");
2915
+ }
2916
+ await options.onSample?.({
2917
+ frameIndex,
2918
+ time: data.time,
2919
+ model,
2920
+ data
2921
+ });
2450
2922
  const cameraFrames = {};
2451
- for (const sequenceCamera of cameras) {
2452
- const { key, ...captureOptions } = sequenceCamera;
2453
- cameraFrames[key] = await captureCameraFrame(
2454
- gl,
2455
- scene,
2456
- camera,
2457
- captureOptions
2458
- );
2923
+ for (const { key, captureOptions, mountedSource, session } of captureSessions) {
2924
+ const resolvedCaptureOptions = resolveCameraCaptureOptions(captureOptions);
2925
+ const cameraFrame = session.captureDataUrl({
2926
+ ...resolvedCaptureOptions,
2927
+ source: mountedSource ?? resolvedCaptureOptions.source
2928
+ });
2929
+ if (requireMountedSources) {
2930
+ assertMatchingMountedCameraSource(
2931
+ key,
2932
+ captureOptions,
2933
+ cameraFrame.source
2934
+ );
2935
+ }
2936
+ cameraSummaries[key] = {
2937
+ key,
2938
+ width: cameraFrame.width,
2939
+ height: cameraFrame.height,
2940
+ source: cameraFrame.source,
2941
+ frameCount: (cameraSummaries[key]?.frameCount ?? 0) + 1,
2942
+ firstFrameIndex: cameraSummaries[key]?.firstFrameIndex ?? frameIndex,
2943
+ lastFrameIndex: frameIndex,
2944
+ firstTimestamp: cameraSummaries[key]?.firstTimestamp ?? data.time,
2945
+ lastTimestamp: data.time
2946
+ };
2947
+ cameraFrames[key] = cameraFrame;
2459
2948
  }
2460
2949
  const frame = {
2461
2950
  frameIndex,
2462
2951
  time: getTime(),
2463
2952
  cameras: cameraFrames
2464
2953
  };
2465
- frames.push(frame);
2954
+ if (retainFrames) {
2955
+ frames.push(frame);
2956
+ }
2957
+ recordedFrameCount += 1;
2466
2958
  await options.onFrame?.(frame);
2467
2959
  }
2468
2960
  } finally {
2961
+ for (const { session } of captureSessions) {
2962
+ session.dispose();
2963
+ }
2469
2964
  pausedRef.current = wasPaused;
2470
2965
  }
2471
2966
  return {
2472
2967
  frames,
2473
2968
  cameraKeys: cameras.map((sequenceCamera) => sequenceCamera.key),
2474
- frameCount: frames.length
2969
+ cameraSummaries,
2970
+ frameCount: recordedFrameCount
2475
2971
  };
2476
2972
  },
2477
- [camera, getTime, gl, reset, scene, stepImmediately]
2973
+ [camera, getTime, gl, mujoco, reset, resolveCameraCaptureOptions, scene]
2478
2974
  );
2479
2975
  const project2DTo3D = useCallback(
2480
2976
  (x, y, cameraPos, lookAt) => {
@@ -2571,6 +3067,7 @@ function MujocoSimProvider({
2571
3067
  getSites,
2572
3068
  getActuators: getActuatorsApi,
2573
3069
  getSensors,
3070
+ getCameras,
2574
3071
  getModelOption,
2575
3072
  setGravity,
2576
3073
  setTimestep: setTimestepApi,
@@ -2629,6 +3126,7 @@ function MujocoSimProvider({
2629
3126
  getSites,
2630
3127
  getActuatorsApi,
2631
3128
  getSensors,
3129
+ getCameras,
2632
3130
  getModelOption,
2633
3131
  setGravity,
2634
3132
  setTimestepApi,
@@ -5421,6 +5919,58 @@ function useCameraSequenceRecorder() {
5421
5919
  reset
5422
5920
  };
5423
5921
  }
5922
+ function useMountedCameraSequenceRecorder(defaultOptions = {}) {
5923
+ const mujoco = useMujoco();
5924
+ const [status, setStatus] = useState("idle");
5925
+ const [error, setError] = useState(null);
5926
+ const reset = useCallback(() => {
5927
+ setStatus("idle");
5928
+ setError(null);
5929
+ }, []);
5930
+ const createPlan = useCallback(
5931
+ (cameraKeys, options = {}) => {
5932
+ if (!mujoco.api) {
5933
+ throw new Error("MuJoCo scene is not ready for mounted camera sequence planning.");
5934
+ }
5935
+ return createMountedCameraFrameSequencePlanFromApi(mujoco.api, cameraKeys, {
5936
+ ...defaultOptions,
5937
+ ...options
5938
+ });
5939
+ },
5940
+ [defaultOptions, mujoco.api]
5941
+ );
5942
+ const record = useCallback(
5943
+ async (options) => {
5944
+ if (!mujoco.api) {
5945
+ throw new Error("MuJoCo scene is not ready for mounted camera sequence recording.");
5946
+ }
5947
+ setStatus("capturing");
5948
+ setError(null);
5949
+ try {
5950
+ const result = await recordMountedCameraFrameSequence(mujoco.api, {
5951
+ ...defaultOptions,
5952
+ ...options
5953
+ });
5954
+ setStatus("captured");
5955
+ return result;
5956
+ } catch (nextError) {
5957
+ const error2 = nextError instanceof Error ? nextError : new Error("Unable to record the requested mounted camera sequence.");
5958
+ setError(error2);
5959
+ setStatus("error");
5960
+ throw error2;
5961
+ }
5962
+ },
5963
+ [defaultOptions, mujoco.api]
5964
+ );
5965
+ return {
5966
+ status,
5967
+ error,
5968
+ isRecording: status === "capturing",
5969
+ createPlan,
5970
+ record,
5971
+ reset
5972
+ };
5973
+ }
5424
5974
  function useCtrlNoise(config = {}) {
5425
5975
  const { mjModelRef } = useMujocoContext();
5426
5976
  const configRef = useRef(config);
@@ -5585,6 +6135,12 @@ function useCameraAnimation() {
5585
6135
  *
5586
6136
  * Offscreen camera-frame capture for R3F/MuJoCo scenes.
5587
6137
  */
6138
+ /**
6139
+ * @license
6140
+ * SPDX-License-Identifier: Apache-2.0
6141
+ *
6142
+ * Helpers for resolving dataset camera streams to mounted MuJoCo resources.
6143
+ */
5588
6144
  /**
5589
6145
  * @license
5590
6146
  * SPDX-License-Identifier: Apache-2.0
@@ -5730,6 +6286,12 @@ function useCameraAnimation() {
5730
6286
  *
5731
6287
  * React state wrapper around fixed-camera simulation sequence recording.
5732
6288
  */
6289
+ /**
6290
+ * @license
6291
+ * SPDX-License-Identifier: Apache-2.0
6292
+ *
6293
+ * React state wrapper for named MuJoCo camera/site/body sequence recording.
6294
+ */
5733
6295
  /**
5734
6296
  * @license
5735
6297
  * SPDX-License-Identifier: Apache-2.0
@@ -5760,6 +6322,6 @@ function useCameraAnimation() {
5760
6322
  * useCameraAnimation — composable camera animation hook.
5761
6323
  */
5762
6324
 
5763
- export { Body, ContactListener, ContactMarkers, Debug, DragInteraction, FlexRenderer, IkGizmo, InstancedGeomRenderer, MujocoCanvas, MujocoPhysics, MujocoProvider, MujocoSimProvider, RobotActuators, RobotBodies, RobotGeoms, RobotJoints, RobotKeyframes, RobotResources, RobotSensors, RobotSites, SceneLights, TendonRenderer, TrajectoryPlayer, buildObservation, captureCameraFrame, captureCameraFrameBlob, captureFrame, captureFrameBlob, createContiguousControlGroup, createController, createControllerHook, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getContact, getControlMap, getName, loadScene, registerRobotResources, renderCameraFrameToCanvas, resolveControlGroup, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useCameraFrameCapture, useCameraSequenceRecorder, useContactEvents, useContacts, useCtrl, useCtrlNoise, useFrameCapture, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMujoco, useMujocoWasm, useObservation, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
6325
+ export { Body, ContactListener, ContactMarkers, Debug, DragInteraction, FlexRenderer, IkGizmo, InstancedGeomRenderer, MountedCameraFrameSequenceReadinessStatus, MujocoCanvas, MujocoPhysics, MujocoProvider, MujocoSimProvider, SceneLights, TendonRenderer, TrajectoryPlayer, buildObservation, captureCameraFrame, captureCameraFrameBlob, captureFrame, captureFrameBlob, createCameraFrameCaptureSession, createContiguousControlGroup, createController, createControllerHook, createMountedCameraFrameSequencePlan, createMountedCameraFrameSequencePlanFromApi, createMountedCameraFrameSequenceReadiness, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getCameraFrameCaptureSourceTarget, getControlMap, getMountedCameraFrameCaptureSource, getName, isMountedCameraFrameCaptureSource, loadScene, recordMountedCameraFrameSequence, renderCameraFrameToCanvas, resolveControlGroup, resolveMountedCameraFrameSource, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useCameraFrameCapture, useCameraSequenceRecorder, useContactEvents, useContacts, useCtrl, useCtrlNoise, useFrameCapture, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMountedCameraSequenceRecorder, useMujoco, useMujocoWasm, useObservation, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
5764
6326
  //# sourceMappingURL=index.js.map
5765
6327
  //# sourceMappingURL=index.js.map