mujoco-react 9.1.0 → 9.2.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
@@ -4,7 +4,7 @@ import defaultMujocoWasmUrl from '@mujoco/mujoco/mujoco.wasm?url';
4
4
  import { createContext, forwardRef, useEffect, useContext, useState, useRef, useCallback, useMemo, useLayoutEffect } from 'react';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
6
6
  import { Canvas, useThree, useFrame } from '@react-three/fiber';
7
- import * as THREE11 from 'three';
7
+ import * as THREE12 from 'three';
8
8
  import { PivotControls } from '@react-three/drei';
9
9
 
10
10
  var MujocoContext = createContext({
@@ -178,16 +178,16 @@ function withContacts(data, read) {
178
178
  contacts.delete?.();
179
179
  }
180
180
  }
181
- var CapsuleGeometry = class extends THREE11.BufferGeometry {
181
+ var CapsuleGeometry = class extends THREE12.BufferGeometry {
182
182
  parameters;
183
183
  constructor(radius = 1, length = 1, capSegments = 4, radialSegments = 8) {
184
184
  super();
185
185
  this.type = "CapsuleGeometry";
186
186
  this.parameters = { radius, length, capSegments, radialSegments };
187
- const path = new THREE11.Path();
187
+ const path = new THREE12.Path();
188
188
  path.absarc(0, -length / 2, radius, Math.PI * 1.5, 0, false);
189
189
  path.absarc(0, length / 2, radius, 0, Math.PI * 0.5, false);
190
- const latheGeometry = new THREE11.LatheGeometry(path.getPoints(capSegments), radialSegments);
190
+ const latheGeometry = new THREE12.LatheGeometry(path.getPoints(capSegments), radialSegments);
191
191
  const self = this;
192
192
  self.setIndex(latheGeometry.getIndex());
193
193
  self.setAttribute("position", latheGeometry.getAttribute("position"));
@@ -195,27 +195,27 @@ var CapsuleGeometry = class extends THREE11.BufferGeometry {
195
195
  self.setAttribute("uv", latheGeometry.getAttribute("uv"));
196
196
  }
197
197
  };
198
- var Reflector = class extends THREE11.Mesh {
198
+ var Reflector = class extends THREE12.Mesh {
199
199
  isReflector = true;
200
200
  camera;
201
- reflectorPlane = new THREE11.Plane();
202
- normal = new THREE11.Vector3();
203
- reflectorWorldPosition = new THREE11.Vector3();
204
- cameraWorldPosition = new THREE11.Vector3();
205
- rotationMatrix = new THREE11.Matrix4();
206
- lookAtPosition = new THREE11.Vector3(0, 0, -1);
207
- clipPlane = new THREE11.Vector4();
208
- view = new THREE11.Vector3();
209
- target = new THREE11.Vector3();
210
- q = new THREE11.Vector4();
211
- textureMatrix = new THREE11.Matrix4();
201
+ reflectorPlane = new THREE12.Plane();
202
+ normal = new THREE12.Vector3();
203
+ reflectorWorldPosition = new THREE12.Vector3();
204
+ cameraWorldPosition = new THREE12.Vector3();
205
+ rotationMatrix = new THREE12.Matrix4();
206
+ lookAtPosition = new THREE12.Vector3(0, 0, -1);
207
+ clipPlane = new THREE12.Vector4();
208
+ view = new THREE12.Vector3();
209
+ target = new THREE12.Vector3();
210
+ q = new THREE12.Vector4();
211
+ textureMatrix = new THREE12.Matrix4();
212
212
  virtualCamera;
213
213
  renderTarget;
214
214
  constructor(geometry, options = {}) {
215
215
  super(geometry);
216
216
  this.type = "Reflector";
217
- this.camera = new THREE11.PerspectiveCamera();
218
- const color = options.color !== void 0 ? new THREE11.Color(options.color) : new THREE11.Color(8355711);
217
+ this.camera = new THREE12.PerspectiveCamera();
218
+ const color = options.color !== void 0 ? new THREE12.Color(options.color) : new THREE12.Color(8355711);
219
219
  const textureWidth = options.textureWidth || 512;
220
220
  const textureHeight = options.textureHeight || 512;
221
221
  const clipBias = options.clipBias || 0;
@@ -223,11 +223,11 @@ var Reflector = class extends THREE11.Mesh {
223
223
  const blendTexture = options.texture || void 0;
224
224
  const mixStrength = options.mixStrength !== void 0 ? options.mixStrength : 0.25;
225
225
  this.virtualCamera = this.camera;
226
- this.renderTarget = new THREE11.WebGLRenderTarget(textureWidth, textureHeight, {
226
+ this.renderTarget = new THREE12.WebGLRenderTarget(textureWidth, textureHeight, {
227
227
  samples: multisample,
228
- type: THREE11.HalfFloatType
228
+ type: THREE12.HalfFloatType
229
229
  });
230
- this.material = new THREE11.MeshPhysicalMaterial({
230
+ this.material = new THREE12.MeshPhysicalMaterial({
231
231
  map: blendTexture,
232
232
  color,
233
233
  roughness: 0.5,
@@ -353,7 +353,7 @@ var GeomBuilder = class {
353
353
  const pos = mjModel.geom_pos.subarray(g * 3, g * 3 + 3);
354
354
  const quat = mjModel.geom_quat.subarray(g * 4, g * 4 + 4);
355
355
  const matId = mjModel.geom_matid[g];
356
- const color = new THREE11.Color(16777215);
356
+ const color = new THREE12.Color(16777215);
357
357
  let opacity = 1;
358
358
  if (matId >= 0) {
359
359
  const rgba = mjModel.mat_rgba.subarray(matId * 4, matId * 4 + 4);
@@ -368,16 +368,16 @@ var GeomBuilder = class {
368
368
  let geo = null;
369
369
  const getVal = (v) => v?.value ?? v;
370
370
  if (type === getVal(MG.mjGEOM_PLANE)) {
371
- geo = new THREE11.PlaneGeometry(size[0] * 2 || 5, size[1] * 2 || 5);
371
+ geo = new THREE12.PlaneGeometry(size[0] * 2 || 5, size[1] * 2 || 5);
372
372
  } else if (type === getVal(MG.mjGEOM_SPHERE)) {
373
- geo = new THREE11.SphereGeometry(size[0], 24, 24);
373
+ geo = new THREE12.SphereGeometry(size[0], 24, 24);
374
374
  } else if (type === getVal(MG.mjGEOM_CAPSULE)) {
375
375
  geo = new CapsuleGeometry(size[0], size[1] * 2, 24, 12);
376
376
  geo.rotateX(Math.PI / 2);
377
377
  } else if (type === getVal(MG.mjGEOM_BOX)) {
378
- geo = new THREE11.BoxGeometry(size[0] * 2, size[1] * 2, size[2] * 2);
378
+ geo = new THREE12.BoxGeometry(size[0] * 2, size[1] * 2, size[2] * 2);
379
379
  } else if (type === getVal(MG.mjGEOM_CYLINDER)) {
380
- geo = new THREE11.CylinderGeometry(size[0], size[0], size[1] * 2, 24);
380
+ geo = new THREE12.CylinderGeometry(size[0], size[0], size[1] * 2, 24);
381
381
  geo.rotateX(Math.PI / 2);
382
382
  } else if (type === getVal(MG.mjGEOM_MESH)) {
383
383
  const mId = mjModel.geom_dataid[g];
@@ -385,8 +385,8 @@ var GeomBuilder = class {
385
385
  const vNum = mjModel.mesh_vertnum[mId];
386
386
  const fAdr = mjModel.mesh_faceadr[mId];
387
387
  const fNum = mjModel.mesh_facenum[mId];
388
- geo = new THREE11.BufferGeometry();
389
- geo.setAttribute("position", new THREE11.Float32BufferAttribute(mjModel.mesh_vert.subarray(vAdr * 3, (vAdr + vNum) * 3), 3));
388
+ geo = new THREE12.BufferGeometry();
389
+ geo.setAttribute("position", new THREE12.Float32BufferAttribute(mjModel.mesh_vert.subarray(vAdr * 3, (vAdr + vNum) * 3), 3));
390
390
  geo.setIndex(Array.from(mjModel.mesh_face.subarray(fAdr * 3, (fAdr + fNum) * 3)));
391
391
  geo.computeVertexNormals();
392
392
  }
@@ -401,7 +401,7 @@ var GeomBuilder = class {
401
401
  mixStrength: 0.25
402
402
  });
403
403
  } else {
404
- mesh = new THREE11.Mesh(geo, new THREE11.MeshStandardMaterial({
404
+ mesh = new THREE12.Mesh(geo, new THREE12.MeshStandardMaterial({
405
405
  color,
406
406
  transparent: opacity < 1,
407
407
  opacity,
@@ -1206,7 +1206,7 @@ function SceneRenderer(props) {
1206
1206
  }
1207
1207
  const refs = [];
1208
1208
  for (let i = 0; i < model.nbody; i++) {
1209
- const bodyGroup = new THREE11.Group();
1209
+ const bodyGroup = new THREE12.Group();
1210
1210
  bodyGroup.userData.bodyID = i;
1211
1211
  const bodyName = getName(model, model.name_bodyadr[i]);
1212
1212
  if (!hiddenBodiesRef.current.has(bodyName)) {
@@ -1235,9 +1235,9 @@ function SceneRenderer(props) {
1235
1235
  const alpha = interpolation.alpha;
1236
1236
  const i3 = i * 3;
1237
1237
  ref.position.set(
1238
- THREE11.MathUtils.lerp(interpolation.previousXpos[i3], interpolation.currentXpos[i3], alpha),
1239
- THREE11.MathUtils.lerp(interpolation.previousXpos[i3 + 1], interpolation.currentXpos[i3 + 1], alpha),
1240
- THREE11.MathUtils.lerp(interpolation.previousXpos[i3 + 2], interpolation.currentXpos[i3 + 2], alpha)
1238
+ THREE12.MathUtils.lerp(interpolation.previousXpos[i3], interpolation.currentXpos[i3], alpha),
1239
+ THREE12.MathUtils.lerp(interpolation.previousXpos[i3 + 1], interpolation.currentXpos[i3 + 1], alpha),
1240
+ THREE12.MathUtils.lerp(interpolation.previousXpos[i3 + 2], interpolation.currentXpos[i3 + 2], alpha)
1241
1241
  );
1242
1242
  const i4 = i * 4;
1243
1243
  _previousQuat.set(
@@ -1292,8 +1292,8 @@ function SceneRenderer(props) {
1292
1292
  }
1293
1293
  );
1294
1294
  }
1295
- var _previousQuat = new THREE11.Quaternion();
1296
- var _currentQuat = new THREE11.Quaternion();
1295
+ var _previousQuat = new THREE12.Quaternion();
1296
+ var _currentQuat = new THREE12.Quaternion();
1297
1297
  function isTargetRef(target) {
1298
1298
  return Boolean(target && typeof target === "object" && "current" in target);
1299
1299
  }
@@ -1402,6 +1402,124 @@ function useFrameCapture(defaultOptions = {}) {
1402
1402
  reset
1403
1403
  };
1404
1404
  }
1405
+ function toVector3(value, fallback) {
1406
+ if (!value) return fallback.clone();
1407
+ return value instanceof THREE12.Vector3 ? value.clone() : new THREE12.Vector3(value[0], value[1], value[2]);
1408
+ }
1409
+ function applyCameraPose(camera, options, fallbackCamera) {
1410
+ camera.position.copy(toVector3(options.position, fallbackCamera.position));
1411
+ camera.up.copy(toVector3(options.up, fallbackCamera.up));
1412
+ if (options.quaternion) {
1413
+ if (options.quaternion instanceof THREE12.Quaternion) {
1414
+ camera.quaternion.copy(options.quaternion);
1415
+ } else {
1416
+ camera.quaternion.set(
1417
+ options.quaternion[0],
1418
+ options.quaternion[1],
1419
+ options.quaternion[2],
1420
+ options.quaternion[3]
1421
+ );
1422
+ }
1423
+ } else if (options.lookAt) {
1424
+ camera.lookAt(toVector3(options.lookAt, new THREE12.Vector3()));
1425
+ } else {
1426
+ camera.quaternion.copy(fallbackCamera.quaternion);
1427
+ }
1428
+ camera.updateMatrixWorld();
1429
+ }
1430
+ function createCaptureCamera(options, fallbackCamera, width, height) {
1431
+ const camera = options.camera ? options.camera.clone() : fallbackCamera instanceof THREE12.PerspectiveCamera ? fallbackCamera.clone() : new THREE12.PerspectiveCamera(45, width / height, 0.01, 100);
1432
+ if (camera instanceof THREE12.PerspectiveCamera) {
1433
+ camera.aspect = width / height;
1434
+ camera.fov = options.fov ?? camera.fov;
1435
+ camera.near = options.near ?? camera.near;
1436
+ camera.far = options.far ?? camera.far;
1437
+ camera.updateProjectionMatrix();
1438
+ }
1439
+ applyCameraPose(camera, options, fallbackCamera);
1440
+ return camera;
1441
+ }
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.");
1451
+ }
1452
+ const imageData = context.createImageData(width, height);
1453
+ const rowBytes = width * 4;
1454
+ for (let y = 0; y < height; y += 1) {
1455
+ const sourceStart = (height - y - 1) * rowBytes;
1456
+ const targetStart = y * rowBytes;
1457
+ imageData.data.set(
1458
+ pixels.subarray(sourceStart, sourceStart + rowBytes),
1459
+ targetStart
1460
+ );
1461
+ }
1462
+ context.putImageData(imageData, 0, 0);
1463
+ return canvas;
1464
+ }
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));
1468
+ const camera = createCaptureCamera(options, fallbackCamera, width, height);
1469
+ const target = new THREE12.WebGLRenderTarget(width, height, {
1470
+ format: THREE12.RGBAFormat,
1471
+ type: THREE12.UnsignedByteType
1472
+ });
1473
+ const previousTarget = renderer.getRenderTarget();
1474
+ const previousXrEnabled = renderer.xr.enabled;
1475
+ scene.updateMatrixWorld(true);
1476
+ 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 };
1483
+ } finally {
1484
+ renderer.setRenderTarget(previousTarget);
1485
+ renderer.xr.enabled = previousXrEnabled;
1486
+ target.dispose();
1487
+ }
1488
+ }
1489
+ async function captureCameraFrame(renderer, scene, fallbackCamera, options = {}) {
1490
+ const type = options.type ?? "image/png";
1491
+ const result = renderCameraFrameToCanvas(
1492
+ renderer,
1493
+ scene,
1494
+ fallbackCamera,
1495
+ options
1496
+ );
1497
+ return {
1498
+ ...result,
1499
+ dataUrl: result.canvas.toDataURL(type, options.quality),
1500
+ type
1501
+ };
1502
+ }
1503
+ async function captureCameraFrameBlob(renderer, scene, fallbackCamera, options = {}) {
1504
+ const type = options.type ?? "image/png";
1505
+ const result = renderCameraFrameToCanvas(
1506
+ renderer,
1507
+ scene,
1508
+ fallbackCamera,
1509
+ options
1510
+ );
1511
+ const blob = await new Promise((resolve, reject) => {
1512
+ result.canvas.toBlob(
1513
+ (nextBlob) => {
1514
+ if (nextBlob) resolve(nextBlob);
1515
+ else reject(new Error("Camera frame capture did not produce a Blob."));
1516
+ },
1517
+ type,
1518
+ options.quality
1519
+ );
1520
+ });
1521
+ return { ...result, blob, type };
1522
+ }
1405
1523
  var JOINT_TYPE_NAMES2 = ["free", "ball", "slide", "hinge"];
1406
1524
  var GEOM_TYPE_NAMES = ["plane", "hfield", "sphere", "capsule", "ellipsoid", "cylinder", "box", "mesh"];
1407
1525
  var SENSOR_TYPE_NAMES = {
@@ -1477,8 +1595,13 @@ var _applyPoint = new Float64Array(3);
1477
1595
  var _rayPnt = new Float64Array(3);
1478
1596
  var _rayVec = new Float64Array(3);
1479
1597
  var _rayGeomId = new Int32Array(1);
1480
- var _projRaycaster = new THREE11.Raycaster();
1481
- var _projNdc = new THREE11.Vector2();
1598
+ var _projRaycaster = new THREE12.Raycaster();
1599
+ var _projNdc = new THREE12.Vector2();
1600
+ function waitForNextAnimationFrame2() {
1601
+ return new Promise((resolve) => {
1602
+ requestAnimationFrame(() => resolve());
1603
+ });
1604
+ }
1482
1605
  var MujocoSimContext = createContext(null);
1483
1606
  function useMujocoContext() {
1484
1607
  const ctx = useContext(MujocoSimContext);
@@ -1563,7 +1686,7 @@ function MujocoSimProvider({
1563
1686
  interpolate,
1564
1687
  children
1565
1688
  }) {
1566
- const { gl, camera } = useThree();
1689
+ const { gl, camera, scene } = useThree();
1567
1690
  const [status, setStatus] = useState("loading");
1568
1691
  const mjModelRef = useRef(null);
1569
1692
  const mjDataRef = useRef(null);
@@ -1812,6 +1935,27 @@ function MujocoSimProvider({
1812
1935
  const step = useCallback((n = 1) => {
1813
1936
  stepsToRunRef.current = n;
1814
1937
  }, []);
1938
+ const stepImmediately = useCallback((steps = 1) => {
1939
+ const model = mjModelRef.current;
1940
+ const data = mjDataRef.current;
1941
+ if (!model || !data) return false;
1942
+ for (let stepIndex = 0; stepIndex < steps; stepIndex += 1) {
1943
+ for (let i = 0; i < model.nv; i += 1) {
1944
+ data.qfrc_applied[i] = 0;
1945
+ }
1946
+ for (const cb of beforeStepCallbacks.current) {
1947
+ cb({ model, data });
1948
+ }
1949
+ mujoco.mj_step(model, data);
1950
+ for (const cb of afterStepCallbacks.current) {
1951
+ cb({ model, data });
1952
+ }
1953
+ onStepRef.current?.({ time: data.time, model, data });
1954
+ }
1955
+ physicsAccumulatorRef.current = 0;
1956
+ interpolationStateRef.current.valid = false;
1957
+ return true;
1958
+ }, [mujoco]);
1815
1959
  const getTime = useCallback(() => {
1816
1960
  return mjDataRef.current?.time ?? 0;
1817
1961
  }, []);
@@ -2122,7 +2266,7 @@ function MujocoSimProvider({
2122
2266
  const geomId = _rayGeomId[0];
2123
2267
  const bodyId = geomId >= 0 ? model.geom_bodyid[geomId] : -1;
2124
2268
  return {
2125
- point: new THREE11.Vector3(
2269
+ point: new THREE12.Vector3(
2126
2270
  origin.x + dir.x * dist,
2127
2271
  origin.y + dir.y * dist,
2128
2272
  origin.z + dir.z * dist
@@ -2268,6 +2412,70 @@ function MujocoSimProvider({
2268
2412
  },
2269
2413
  [gl]
2270
2414
  );
2415
+ const captureCameraFrameApi = useCallback(
2416
+ (options = {}) => {
2417
+ return captureCameraFrame(gl, scene, camera, options);
2418
+ },
2419
+ [camera, gl, scene]
2420
+ );
2421
+ const captureCameraFrameBlobApi = useCallback(
2422
+ (options = {}) => {
2423
+ return captureCameraFrameBlob(gl, scene, camera, options);
2424
+ },
2425
+ [camera, gl, scene]
2426
+ );
2427
+ const recordCameraSequenceApi = useCallback(
2428
+ async (options) => {
2429
+ const frameCount = Math.max(0, Math.floor(options.frames));
2430
+ const stepsPerFrame = Math.max(1, Math.floor(options.stepsPerFrame ?? 1));
2431
+ const cameras = options.cameras;
2432
+ const frames = [];
2433
+ const wasPaused = pausedRef.current;
2434
+ if (frameCount === 0 || cameras.length === 0) {
2435
+ return {
2436
+ frames,
2437
+ cameraKeys: cameras.map((sequenceCamera) => sequenceCamera.key),
2438
+ frameCount: 0
2439
+ };
2440
+ }
2441
+ try {
2442
+ pausedRef.current = true;
2443
+ stepsToRunRef.current = 0;
2444
+ if (options.reset) reset();
2445
+ for (let frameIndex = 0; frameIndex < frameCount; frameIndex += 1) {
2446
+ if (frameIndex > 0 || options.captureInitialFrame === false) {
2447
+ stepImmediately(stepsPerFrame);
2448
+ }
2449
+ await waitForNextAnimationFrame2();
2450
+ 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
+ );
2459
+ }
2460
+ const frame = {
2461
+ frameIndex,
2462
+ time: getTime(),
2463
+ cameras: cameraFrames
2464
+ };
2465
+ frames.push(frame);
2466
+ await options.onFrame?.(frame);
2467
+ }
2468
+ } finally {
2469
+ pausedRef.current = wasPaused;
2470
+ }
2471
+ return {
2472
+ frames,
2473
+ cameraKeys: cameras.map((sequenceCamera) => sequenceCamera.key),
2474
+ frameCount: frames.length
2475
+ };
2476
+ },
2477
+ [camera, getTime, gl, reset, scene, stepImmediately]
2478
+ );
2271
2479
  const project2DTo3D = useCallback(
2272
2480
  (x, y, cameraPos, lookAt) => {
2273
2481
  const virtCam = camera.clone();
@@ -2278,9 +2486,9 @@ function MujocoSimProvider({
2278
2486
  _projNdc.set(x * 2 - 1, -(y * 2 - 1));
2279
2487
  _projRaycaster.setFromCamera(_projNdc, virtCam);
2280
2488
  const objects = [];
2281
- const scene = camera.parent;
2282
- if (scene) {
2283
- scene.traverse((c) => {
2489
+ const scene2 = camera.parent;
2490
+ if (scene2) {
2491
+ scene2.traverse((c) => {
2284
2492
  if (c.isMesh) objects.push(c);
2285
2493
  });
2286
2494
  }
@@ -2378,6 +2586,9 @@ function MujocoSimProvider({
2378
2586
  getCanvasSnapshot,
2379
2587
  captureFrame: captureFrameApi,
2380
2588
  captureFrameBlob: captureFrameBlobApi,
2589
+ captureCameraFrame: captureCameraFrameApi,
2590
+ captureCameraFrameBlob: captureCameraFrameBlobApi,
2591
+ recordCameraSequence: recordCameraSequenceApi,
2381
2592
  project2DTo3D,
2382
2593
  setBodyMass,
2383
2594
  setGeomFriction,
@@ -2433,6 +2644,9 @@ function MujocoSimProvider({
2433
2644
  getCanvasSnapshot,
2434
2645
  captureFrameApi,
2435
2646
  captureFrameBlobApi,
2647
+ captureCameraFrameApi,
2648
+ captureCameraFrameBlobApi,
2649
+ recordCameraSequenceApi,
2436
2650
  project2DTo3D,
2437
2651
  setBodyMass,
2438
2652
  setGeomFriction,
@@ -2899,7 +3113,7 @@ function solve6x6(A, b, x) {
2899
3113
  }
2900
3114
 
2901
3115
  // src/hooks/useIkController.ts
2902
- var _syncMat4 = new THREE11.Matrix4();
3116
+ var _syncMat4 = new THREE12.Matrix4();
2903
3117
  function syncGizmoToSite(data, siteId, target) {
2904
3118
  if (siteId === -1) return;
2905
3119
  const sitePos = data.site_xpos.subarray(siteId * 3, siteId * 3 + 3);
@@ -2931,7 +3145,7 @@ var useIkController = createControllerHook(
2931
3145
  const { mjModelRef, mjDataRef, mujocoRef, resetCallbacks, status } = useMujocoContext();
2932
3146
  const ikEnabledRef = useRef(false);
2933
3147
  const ikCalculatingRef = useRef(false);
2934
- const ikTargetRef = useRef(new THREE11.Group());
3148
+ const ikTargetRef = useRef(new THREE12.Group());
2935
3149
  const siteIdRef = useRef(-1);
2936
3150
  const controlGroupRef = useRef(null);
2937
3151
  const genericIkRef = useRef(new GenericIK(mujocoRef.current));
@@ -2939,10 +3153,10 @@ var useIkController = createControllerHook(
2939
3153
  const needsInitialSync = useRef(true);
2940
3154
  const gizmoAnimRef = useRef({
2941
3155
  active: false,
2942
- startPos: new THREE11.Vector3(),
2943
- endPos: new THREE11.Vector3(),
2944
- startRot: new THREE11.Quaternion(),
2945
- endRot: new THREE11.Quaternion(),
3156
+ startPos: new THREE12.Vector3(),
3157
+ endPos: new THREE12.Vector3(),
3158
+ startRot: new THREE12.Quaternion(),
3159
+ endRot: new THREE12.Quaternion(),
2946
3160
  startTime: 0,
2947
3161
  duration: 1e3
2948
3162
  });
@@ -3087,8 +3301,8 @@ var useIkController = createControllerHook(
3087
3301
  const target = ikTargetRef.current;
3088
3302
  if (!target) return;
3089
3303
  const targetPos = pos.clone();
3090
- const targetRot = new THREE11.Quaternion().setFromEuler(
3091
- new THREE11.Euler(Math.PI, 0, 0)
3304
+ const targetRot = new THREE12.Quaternion().setFromEuler(
3305
+ new THREE12.Euler(Math.PI, 0, 0)
3092
3306
  );
3093
3307
  if (duration > 0) {
3094
3308
  const ga = gizmoAnimRef.current;
@@ -3113,7 +3327,7 @@ var useIkController = createControllerHook(
3113
3327
  if (!ikCalculatingRef.current || !target) return null;
3114
3328
  return {
3115
3329
  pos: target.position.clone(),
3116
- rot: new THREE11.Euler().setFromQuaternion(target.quaternion)
3330
+ rot: new THREE12.Euler().setFromQuaternion(target.quaternion)
3117
3331
  };
3118
3332
  },
3119
3333
  []
@@ -3209,10 +3423,10 @@ function Body({
3209
3423
  if (!hasChildren) return null;
3210
3424
  return /* @__PURE__ */ jsx("group", { ref: groupRef, children });
3211
3425
  }
3212
- var _mat4 = new THREE11.Matrix4();
3213
- var _pos = new THREE11.Vector3();
3214
- var _quat = new THREE11.Quaternion();
3215
- var _scale = new THREE11.Vector3(1, 1, 1);
3426
+ var _mat4 = new THREE12.Matrix4();
3427
+ var _pos = new THREE12.Vector3();
3428
+ var _quat = new THREE12.Quaternion();
3429
+ var _scale = new THREE12.Vector3(1, 1, 1);
3216
3430
  function IkGizmo({ controller, siteName, scale = 0.18, onDrag }) {
3217
3431
  const { mjModelRef, mjDataRef, status } = useMujocoContext();
3218
3432
  const { ikTargetRef, siteIdRef, ikEnabledRef, setIkEnabled } = controller;
@@ -3304,7 +3518,7 @@ function IkGizmo({ controller, siteName, scale = 0.18, onDrag }) {
3304
3518
  }
3305
3519
  ) });
3306
3520
  }
3307
- var _dummy = new THREE11.Object3D();
3521
+ var _dummy = new THREE12.Object3D();
3308
3522
  function ContactMarkers({
3309
3523
  maxContacts = 100,
3310
3524
  radius = 8e-3,
@@ -3348,11 +3562,11 @@ function ContactMarkers({
3348
3562
  var _force = new Float64Array(3);
3349
3563
  var _torque = new Float64Array(3);
3350
3564
  var _point = new Float64Array(3);
3351
- var _bodyPos = new THREE11.Vector3();
3352
- var _bodyQuat = new THREE11.Quaternion();
3353
- var _worldHit = new THREE11.Vector3();
3354
- var _raycaster = new THREE11.Raycaster();
3355
- var _mouse = new THREE11.Vector2();
3565
+ var _bodyPos = new THREE12.Vector3();
3566
+ var _bodyQuat = new THREE12.Quaternion();
3567
+ var _worldHit = new THREE12.Vector3();
3568
+ var _raycaster = new THREE12.Raycaster();
3569
+ var _mouse = new THREE12.Vector2();
3356
3570
  function DragInteraction({
3357
3571
  stiffness = 250,
3358
3572
  showArrow = true,
@@ -3363,16 +3577,16 @@ function DragInteraction({
3363
3577
  const draggingRef = useRef(false);
3364
3578
  const bodyIdRef = useRef(-1);
3365
3579
  const grabDistanceRef = useRef(0);
3366
- const localHitRef = useRef(new THREE11.Vector3());
3367
- const grabWorldRef = useRef(new THREE11.Vector3());
3368
- const mouseWorldRef = useRef(new THREE11.Vector3());
3580
+ const localHitRef = useRef(new THREE12.Vector3());
3581
+ const grabWorldRef = useRef(new THREE12.Vector3());
3582
+ const mouseWorldRef = useRef(new THREE12.Vector3());
3369
3583
  const arrowRef = useRef(null);
3370
3584
  const groupRef = useRef(null);
3371
3585
  useEffect(() => {
3372
3586
  if (!showArrow || !groupRef.current) return;
3373
- const arrow = new THREE11.ArrowHelper(
3374
- new THREE11.Vector3(0, 1, 0),
3375
- new THREE11.Vector3(),
3587
+ const arrow = new THREE12.ArrowHelper(
3588
+ new THREE12.Vector3(0, 1, 0),
3589
+ new THREE12.Vector3(),
3376
3590
  0.1,
3377
3591
  16729156
3378
3592
  );
@@ -3554,7 +3768,7 @@ function useSceneLights(intensity = 1) {
3554
3768
  const dr = lightDiffuse ? lightDiffuse[3 * i] : 1;
3555
3769
  const dg = lightDiffuse ? lightDiffuse[3 * i + 1] : 1;
3556
3770
  const db = lightDiffuse ? lightDiffuse[3 * i + 2] : 1;
3557
- const color = new THREE11.Color(dr, dg, db);
3771
+ const color = new THREE12.Color(dr, dg, db);
3558
3772
  const px = lightPos[3 * i];
3559
3773
  const py = lightPos[3 * i + 1];
3560
3774
  const pz = lightPos[3 * i + 2];
@@ -3562,7 +3776,7 @@ function useSceneLights(intensity = 1) {
3562
3776
  const dy = lightDir[3 * i + 1];
3563
3777
  const dz = lightDir[3 * i + 2];
3564
3778
  if (isDirectional) {
3565
- const light = new THREE11.DirectionalLight(color, finalIntensity);
3779
+ const light = new THREE12.DirectionalLight(color, finalIntensity);
3566
3780
  light.position.set(px, py, pz);
3567
3781
  light.target.position.set(px + dx, py + dy, pz + dz);
3568
3782
  light.castShadow = castShadow;
@@ -3585,7 +3799,7 @@ function useSceneLights(intensity = 1) {
3585
3799
  const cutoff = lightCutoff ? lightCutoff[i] : 45;
3586
3800
  const exponent = lightExponent ? lightExponent[i] : 10;
3587
3801
  const angle = cutoff * Math.PI / 180;
3588
- const light = new THREE11.SpotLight(color, finalIntensity, 0, angle, exponent / 128);
3802
+ const light = new THREE12.SpotLight(color, finalIntensity, 0, angle, exponent / 128);
3589
3803
  light.position.set(px, py, pz);
3590
3804
  light.target.position.set(px + dx, py + dy, pz + dz);
3591
3805
  light.castShadow = castShadow;
@@ -3643,11 +3857,11 @@ var JOINT_COLORS = {
3643
3857
  3: 16776960
3644
3858
  // hinge - yellow
3645
3859
  };
3646
- var _v3a = new THREE11.Vector3();
3647
- new THREE11.Vector3();
3648
- var _quat2 = new THREE11.Quaternion();
3649
- var _contactPos = new THREE11.Vector3();
3650
- var _contactNormal = new THREE11.Vector3();
3860
+ var _v3a = new THREE12.Vector3();
3861
+ new THREE12.Vector3();
3862
+ var _quat2 = new THREE12.Quaternion();
3863
+ var _contactPos = new THREE12.Vector3();
3864
+ var _contactNormal = new THREE12.Vector3();
3651
3865
  var MAX_CONTACT_ARROWS = 50;
3652
3866
  function Debug({
3653
3867
  showGeoms = false,
@@ -3676,21 +3890,21 @@ function Debug({
3676
3890
  let geometry = null;
3677
3891
  switch (type) {
3678
3892
  case 2:
3679
- geometry = new THREE11.SphereGeometry(s[3 * i], 12, 8);
3893
+ geometry = new THREE12.SphereGeometry(s[3 * i], 12, 8);
3680
3894
  break;
3681
3895
  case 3:
3682
- geometry = new THREE11.CapsuleGeometry(s[3 * i], s[3 * i + 1] * 2, 6, 8);
3896
+ geometry = new THREE12.CapsuleGeometry(s[3 * i], s[3 * i + 1] * 2, 6, 8);
3683
3897
  break;
3684
3898
  case 5:
3685
- geometry = new THREE11.CylinderGeometry(s[3 * i], s[3 * i], s[3 * i + 1] * 2, 12);
3899
+ geometry = new THREE12.CylinderGeometry(s[3 * i], s[3 * i], s[3 * i + 1] * 2, 12);
3686
3900
  break;
3687
3901
  case 6:
3688
- geometry = new THREE11.BoxGeometry(s[3 * i] * 2, s[3 * i + 1] * 2, s[3 * i + 2] * 2);
3902
+ geometry = new THREE12.BoxGeometry(s[3 * i] * 2, s[3 * i + 1] * 2, s[3 * i + 2] * 2);
3689
3903
  break;
3690
3904
  }
3691
3905
  if (geometry) {
3692
- const mat = new THREE11.MeshBasicMaterial({ color: 65280, wireframe: true, transparent: true, opacity: 0.3 });
3693
- const mesh = new THREE11.Mesh(geometry, mat);
3906
+ const mat = new THREE12.MeshBasicMaterial({ color: 65280, wireframe: true, transparent: true, opacity: 0.3 });
3907
+ const mesh = new THREE12.Mesh(geometry, mat);
3694
3908
  mesh.userData.geomId = i;
3695
3909
  mesh.userData.bodyId = model.geom_bodyid[i];
3696
3910
  geoms.push(mesh);
@@ -3713,9 +3927,9 @@ function Debug({
3713
3927
  }
3714
3928
  if (maxGeomSize > 0) radius = maxGeomSize * 0.15;
3715
3929
  }
3716
- const geometry = new THREE11.OctahedronGeometry(radius);
3717
- const mat = new THREE11.MeshBasicMaterial({ color: 16711935, depthTest: false });
3718
- const mesh = new THREE11.Mesh(geometry, mat);
3930
+ const geometry = new THREE12.OctahedronGeometry(radius);
3931
+ const mat = new THREE12.MeshBasicMaterial({ color: 16711935, depthTest: false });
3932
+ const mesh = new THREE12.Mesh(geometry, mat);
3719
3933
  mesh.renderOrder = 999;
3720
3934
  mesh.frustumCulled = false;
3721
3935
  mesh.userData.siteId = i;
@@ -3727,9 +3941,9 @@ function Debug({
3727
3941
  ctx.font = "bold 36px monospace";
3728
3942
  ctx.textAlign = "center";
3729
3943
  ctx.fillText(getName(model, model.name_siteadr[i]), 128, 42);
3730
- const tex = new THREE11.CanvasTexture(canvas);
3731
- const spriteMat = new THREE11.SpriteMaterial({ map: tex, depthTest: false, transparent: true });
3732
- const sprite = new THREE11.Sprite(spriteMat);
3944
+ const tex = new THREE12.CanvasTexture(canvas);
3945
+ const spriteMat = new THREE12.SpriteMaterial({ map: tex, depthTest: false, transparent: true });
3946
+ const sprite = new THREE12.Sprite(spriteMat);
3733
3947
  const labelScale = radius * 15;
3734
3948
  sprite.scale.set(labelScale, labelScale * 0.25, 1);
3735
3949
  sprite.position.y = radius * 2;
@@ -3752,9 +3966,9 @@ function Debug({
3752
3966
  }
3753
3967
  }
3754
3968
  const arrowLen = Math.max(maxGeomSize * 0.8, 0.05);
3755
- const arrow = new THREE11.ArrowHelper(
3756
- new THREE11.Vector3(0, 0, 1),
3757
- new THREE11.Vector3(),
3969
+ const arrow = new THREE12.ArrowHelper(
3970
+ new THREE12.Vector3(0, 0, 1),
3971
+ new THREE12.Vector3(),
3758
3972
  arrowLen,
3759
3973
  color,
3760
3974
  arrowLen * 0.25,
@@ -3762,7 +3976,7 @@ function Debug({
3762
3976
  );
3763
3977
  arrow.renderOrder = 999;
3764
3978
  arrow.frustumCulled = false;
3765
- arrow.line.material = new THREE11.LineBasicMaterial({ color, depthTest: false });
3979
+ arrow.line.material = new THREE12.LineBasicMaterial({ color, depthTest: false });
3766
3980
  arrow.cone.material.depthTest = false;
3767
3981
  arrow.line.renderOrder = 999;
3768
3982
  arrow.line.frustumCulled = false;
@@ -3777,9 +3991,9 @@ function Debug({
3777
3991
  }
3778
3992
  if (showCOM) {
3779
3993
  for (let i = 1; i < model.nbody; i++) {
3780
- const geometry = new THREE11.SphereGeometry(5e-3, 6, 6);
3781
- const mat = new THREE11.MeshBasicMaterial({ color: 16711680 });
3782
- const mesh = new THREE11.Mesh(geometry, mat);
3994
+ const geometry = new THREE12.SphereGeometry(5e-3, 6, 6);
3995
+ const mat = new THREE12.MeshBasicMaterial({ color: 16711680 });
3996
+ const mesh = new THREE12.Mesh(geometry, mat);
3783
3997
  mesh.userData.bodyId = i;
3784
3998
  comMarkers.push(mesh);
3785
3999
  }
@@ -3870,9 +4084,9 @@ function Debug({
3870
4084
  contactPoolInitRef.current = true;
3871
4085
  const pool = [];
3872
4086
  for (let i = 0; i < MAX_CONTACT_ARROWS; i++) {
3873
- const arrow = new THREE11.ArrowHelper(
3874
- new THREE11.Vector3(0, 1, 0),
3875
- new THREE11.Vector3(),
4087
+ const arrow = new THREE12.ArrowHelper(
4088
+ new THREE12.Vector3(0, 1, 0),
4089
+ new THREE12.Vector3(),
3876
4090
  0.1,
3877
4091
  16729156,
3878
4092
  0.03,
@@ -3927,9 +4141,9 @@ function Debug({
3927
4141
  showContacts && /* @__PURE__ */ jsx("group", { ref: contactGroupRef })
3928
4142
  ] });
3929
4143
  }
3930
- var DEFAULT_TENDON_COLOR = new THREE11.Color(0.3, 0.3, 0.8);
4144
+ var DEFAULT_TENDON_COLOR = new THREE12.Color(0.3, 0.3, 0.8);
3931
4145
  var DEFAULT_TENDON_WIDTH = 2e-3;
3932
- new THREE11.Vector3();
4146
+ new THREE12.Vector3();
3933
4147
  function TendonRenderer(props) {
3934
4148
  const { mjModelRef, mjDataRef, status } = useMujocoContext();
3935
4149
  const groupRef = useRef(null);
@@ -3943,7 +4157,7 @@ function TendonRenderer(props) {
3943
4157
  if (!model || !data || !group) return;
3944
4158
  const ntendon = model.ntendon ?? 0;
3945
4159
  if (ntendon === 0) return;
3946
- const material = new THREE11.MeshStandardMaterial({
4160
+ const material = new THREE12.MeshStandardMaterial({
3947
4161
  color: DEFAULT_TENDON_COLOR,
3948
4162
  roughness: 0.6,
3949
4163
  metalness: 0.1
@@ -3958,11 +4172,11 @@ function TendonRenderer(props) {
3958
4172
  curves.push(null);
3959
4173
  continue;
3960
4174
  }
3961
- const points = Array.from({ length: wrapNum }, () => new THREE11.Vector3());
3962
- const curve = new THREE11.CatmullRomCurve3(points, false);
4175
+ const points = Array.from({ length: wrapNum }, () => new THREE12.Vector3());
4176
+ const curve = new THREE12.CatmullRomCurve3(points, false);
3963
4177
  const segments = Math.max(wrapNum * 2, 4);
3964
- const geometry = new THREE11.TubeGeometry(curve, segments, DEFAULT_TENDON_WIDTH, 6, false);
3965
- const mesh = new THREE11.Mesh(geometry, material);
4178
+ const geometry = new THREE12.TubeGeometry(curve, segments, DEFAULT_TENDON_WIDTH, 6, false);
4179
+ const mesh = new THREE12.Mesh(geometry, material);
3966
4180
  mesh.frustumCulled = false;
3967
4181
  group.add(mesh);
3968
4182
  meshes.push(mesh);
@@ -4017,11 +4231,11 @@ function TendonRenderer(props) {
4017
4231
  if (curve.points.length !== validCount) {
4018
4232
  curve.points.length = validCount;
4019
4233
  while (curve.points.length < validCount) {
4020
- curve.points.push(new THREE11.Vector3());
4234
+ curve.points.push(new THREE12.Vector3());
4021
4235
  }
4022
4236
  }
4023
4237
  mesh.geometry.dispose();
4024
- mesh.geometry = new THREE11.TubeGeometry(
4238
+ mesh.geometry = new THREE12.TubeGeometry(
4025
4239
  curve,
4026
4240
  Math.max(validCount * 2, 4),
4027
4241
  DEFAULT_TENDON_WIDTH,
@@ -4048,24 +4262,24 @@ function FlexRenderer(props) {
4048
4262
  const vertAdr = model.flex_vertadr[f];
4049
4263
  const vertNum = model.flex_vertnum[f];
4050
4264
  if (vertNum === 0) continue;
4051
- const geometry = new THREE11.BufferGeometry();
4265
+ const geometry = new THREE12.BufferGeometry();
4052
4266
  const positions = new Float32Array(vertNum * 3);
4053
- geometry.setAttribute("position", new THREE11.BufferAttribute(positions, 3));
4267
+ geometry.setAttribute("position", new THREE12.BufferAttribute(positions, 3));
4054
4268
  geometry.computeVertexNormals();
4055
- let color = new THREE11.Color(0.5, 0.5, 0.5);
4269
+ let color = new THREE12.Color(0.5, 0.5, 0.5);
4056
4270
  if (model.flex_rgba) {
4057
- color = new THREE11.Color(
4271
+ color = new THREE12.Color(
4058
4272
  model.flex_rgba[4 * f],
4059
4273
  model.flex_rgba[4 * f + 1],
4060
4274
  model.flex_rgba[4 * f + 2]
4061
4275
  );
4062
4276
  }
4063
- const material = new THREE11.MeshStandardMaterial({
4277
+ const material = new THREE12.MeshStandardMaterial({
4064
4278
  color,
4065
4279
  roughness: 0.7,
4066
- side: THREE11.DoubleSide
4280
+ side: THREE12.DoubleSide
4067
4281
  });
4068
- const mesh = new THREE11.Mesh(geometry, material);
4282
+ const mesh = new THREE12.Mesh(geometry, material);
4069
4283
  mesh.userData.flexId = f;
4070
4284
  mesh.userData.vertAdr = vertAdr;
4071
4285
  mesh.userData.vertNum = vertNum;
@@ -4101,7 +4315,7 @@ function FlexRenderer(props) {
4101
4315
  return /* @__PURE__ */ jsx("group", { ...props, ref: groupRef });
4102
4316
  }
4103
4317
  var GEOM_TYPE_NAMES2 = ["plane", "hfield", "sphere", "capsule", "ellipsoid", "cylinder", "box", "mesh"];
4104
- var _matrix = new THREE11.Matrix4();
4318
+ var _matrix = new THREE12.Matrix4();
4105
4319
  function getGeomInfo(model, geomId) {
4106
4320
  const size = model.geom_size.subarray(geomId * 3, geomId * 3 + 3);
4107
4321
  const type = model.geom_type[geomId];
@@ -4123,10 +4337,10 @@ function geomSignature(model, geomId) {
4123
4337
  return [type, size, mat, data, rgba].join("|");
4124
4338
  }
4125
4339
  function firstMesh(object) {
4126
- if (object instanceof THREE11.Mesh) return object;
4340
+ if (object instanceof THREE12.Mesh) return object;
4127
4341
  let mesh = null;
4128
4342
  object.traverse((child) => {
4129
- if (!mesh && child instanceof THREE11.Mesh) mesh = child;
4343
+ if (!mesh && child instanceof THREE12.Mesh) mesh = child;
4130
4344
  });
4131
4345
  return mesh;
4132
4346
  }
@@ -4555,12 +4769,12 @@ function useActuators() {
4555
4769
  return actuators;
4556
4770
  }, [status, mjModelRef]);
4557
4771
  }
4558
- var _mat42 = new THREE11.Matrix4();
4772
+ var _mat42 = new THREE12.Matrix4();
4559
4773
  function useSitePosition(siteName) {
4560
4774
  const { mjModelRef, mjDataRef, status } = useMujocoContext();
4561
4775
  const siteIdRef = useRef(-1);
4562
- const positionRef = useRef(new THREE11.Vector3());
4563
- const quaternionRef = useRef(new THREE11.Quaternion());
4776
+ const positionRef = useRef(new THREE12.Vector3());
4777
+ const quaternionRef = useRef(new THREE12.Quaternion());
4564
4778
  useEffect(() => {
4565
4779
  const model = mjModelRef.current;
4566
4780
  if (!model || status !== "ready") {
@@ -4751,10 +4965,10 @@ function useJointState(name) {
4751
4965
  function useBodyState(name) {
4752
4966
  const { mjModelRef, status } = useMujocoContext();
4753
4967
  const bodyIdRef = useRef(-1);
4754
- const position = useRef(new THREE11.Vector3());
4755
- const quaternion = useRef(new THREE11.Quaternion());
4756
- const linearVelocity = useRef(new THREE11.Vector3());
4757
- const angularVelocity = useRef(new THREE11.Vector3());
4968
+ const position = useRef(new THREE12.Vector3());
4969
+ const quaternion = useRef(new THREE12.Quaternion());
4970
+ const linearVelocity = useRef(new THREE12.Vector3());
4971
+ const angularVelocity = useRef(new THREE12.Vector3());
4758
4972
  useEffect(() => {
4759
4973
  const model = mjModelRef.current;
4760
4974
  if (!model || status !== "ready") return;
@@ -5108,6 +5322,105 @@ function useVideoRecorder(options = {}) {
5108
5322
  }
5109
5323
  };
5110
5324
  }
5325
+ function useCameraFrameCapture(defaultOptions = {}) {
5326
+ const mujoco = useMujoco();
5327
+ const [status, setStatus] = useState("idle");
5328
+ const [error, setError] = useState(null);
5329
+ const reset = useCallback(() => {
5330
+ setStatus("idle");
5331
+ setError(null);
5332
+ }, []);
5333
+ const capture = useCallback(
5334
+ async (options = {}) => {
5335
+ if (!mujoco.api) {
5336
+ throw new Error("MuJoCo scene is not ready for camera frame capture.");
5337
+ }
5338
+ setStatus("capturing");
5339
+ setError(null);
5340
+ try {
5341
+ const result = await mujoco.api.captureCameraFrame({
5342
+ ...defaultOptions,
5343
+ ...options
5344
+ });
5345
+ setStatus("captured");
5346
+ return result;
5347
+ } catch (nextError) {
5348
+ const error2 = nextError instanceof Error ? nextError : new Error("Unable to capture the requested camera frame.");
5349
+ setError(error2);
5350
+ setStatus("error");
5351
+ throw error2;
5352
+ }
5353
+ },
5354
+ [defaultOptions, mujoco.api]
5355
+ );
5356
+ const captureBlob = useCallback(
5357
+ async (options = {}) => {
5358
+ if (!mujoco.api) {
5359
+ throw new Error("MuJoCo scene is not ready for camera frame capture.");
5360
+ }
5361
+ setStatus("capturing");
5362
+ setError(null);
5363
+ try {
5364
+ const result = await mujoco.api.captureCameraFrameBlob({
5365
+ ...defaultOptions,
5366
+ ...options
5367
+ });
5368
+ setStatus("captured");
5369
+ return result;
5370
+ } catch (nextError) {
5371
+ const error2 = nextError instanceof Error ? nextError : new Error("Unable to capture the requested camera frame.");
5372
+ setError(error2);
5373
+ setStatus("error");
5374
+ throw error2;
5375
+ }
5376
+ },
5377
+ [defaultOptions, mujoco.api]
5378
+ );
5379
+ return {
5380
+ status,
5381
+ error,
5382
+ isCapturing: status === "capturing",
5383
+ capture,
5384
+ captureBlob,
5385
+ reset
5386
+ };
5387
+ }
5388
+ function useCameraSequenceRecorder() {
5389
+ const mujoco = useMujoco();
5390
+ const [status, setStatus] = useState("idle");
5391
+ const [error, setError] = useState(null);
5392
+ const reset = useCallback(() => {
5393
+ setStatus("idle");
5394
+ setError(null);
5395
+ }, []);
5396
+ const record = useCallback(
5397
+ async (options) => {
5398
+ if (!mujoco.api) {
5399
+ throw new Error("MuJoCo scene is not ready for camera sequence recording.");
5400
+ }
5401
+ setStatus("capturing");
5402
+ setError(null);
5403
+ try {
5404
+ const result = await mujoco.api.recordCameraSequence(options);
5405
+ setStatus("captured");
5406
+ return result;
5407
+ } catch (nextError) {
5408
+ const error2 = nextError instanceof Error ? nextError : new Error("Unable to record the requested camera sequence.");
5409
+ setError(error2);
5410
+ setStatus("error");
5411
+ throw error2;
5412
+ }
5413
+ },
5414
+ [mujoco.api]
5415
+ );
5416
+ return {
5417
+ status,
5418
+ error,
5419
+ isRecording: status === "capturing",
5420
+ record,
5421
+ reset
5422
+ };
5423
+ }
5111
5424
  function useCtrlNoise(config = {}) {
5112
5425
  const { mjModelRef } = useMujocoContext();
5113
5426
  const configRef = useRef(config);
@@ -5159,7 +5472,7 @@ function useSelectionHighlight(bodyId, options = {}) {
5159
5472
  }
5160
5473
  }
5161
5474
  prevRef.current = [];
5162
- const highlightColor = new THREE11.Color(color);
5475
+ const highlightColor = new THREE12.Color(color);
5163
5476
  for (const mesh of meshes) {
5164
5477
  const mat = mesh.material;
5165
5478
  if (mat.emissive) {
@@ -5186,15 +5499,15 @@ function useSelectionHighlight(bodyId, options = {}) {
5186
5499
  }
5187
5500
  function useCameraAnimation() {
5188
5501
  const { camera } = useThree();
5189
- const orbitTargetRef = useRef(new THREE11.Vector3(0, 0, 0));
5502
+ const orbitTargetRef = useRef(new THREE12.Vector3(0, 0, 0));
5190
5503
  const cameraAnimRef = useRef({
5191
5504
  active: false,
5192
- startPos: new THREE11.Vector3(),
5193
- endPos: new THREE11.Vector3(),
5194
- startRot: new THREE11.Quaternion(),
5195
- endRot: new THREE11.Quaternion(),
5196
- startTarget: new THREE11.Vector3(),
5197
- endTarget: new THREE11.Vector3(),
5505
+ startPos: new THREE12.Vector3(),
5506
+ endPos: new THREE12.Vector3(),
5507
+ startRot: new THREE12.Quaternion(),
5508
+ endRot: new THREE12.Quaternion(),
5509
+ startTarget: new THREE12.Vector3(),
5510
+ endTarget: new THREE12.Vector3(),
5198
5511
  startTime: 0,
5199
5512
  duration: 0,
5200
5513
  resolve: null
@@ -5266,6 +5579,12 @@ function useCameraAnimation() {
5266
5579
  *
5267
5580
  * useFrameCapture — still-frame capture for canvas-backed MuJoCo/R3F scenes.
5268
5581
  */
5582
+ /**
5583
+ * @license
5584
+ * SPDX-License-Identifier: Apache-2.0
5585
+ *
5586
+ * Offscreen camera-frame capture for R3F/MuJoCo scenes.
5587
+ */
5269
5588
  /**
5270
5589
  * @license
5271
5590
  * SPDX-License-Identifier: Apache-2.0
@@ -5399,6 +5718,18 @@ function useCameraAnimation() {
5399
5718
  *
5400
5719
  * useVideoRecorder — canvas video recording hook (spec 13.3)
5401
5720
  */
5721
+ /**
5722
+ * @license
5723
+ * SPDX-License-Identifier: Apache-2.0
5724
+ *
5725
+ * React state wrapper around MuJoCo/R3F offscreen camera-frame capture.
5726
+ */
5727
+ /**
5728
+ * @license
5729
+ * SPDX-License-Identifier: Apache-2.0
5730
+ *
5731
+ * React state wrapper around fixed-camera simulation sequence recording.
5732
+ */
5402
5733
  /**
5403
5734
  * @license
5404
5735
  * SPDX-License-Identifier: Apache-2.0
@@ -5429,6 +5760,6 @@ function useCameraAnimation() {
5429
5760
  * useCameraAnimation — composable camera animation hook.
5430
5761
  */
5431
5762
 
5432
- 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, captureFrame, captureFrameBlob, createContiguousControlGroup, createController, createControllerHook, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getContact, getControlMap, getName, loadScene, registerRobotResources, resolveControlGroup, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useFrameCapture, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMujoco, useMujocoWasm, useObservation, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
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 };
5433
5764
  //# sourceMappingURL=index.js.map
5434
5765
  //# sourceMappingURL=index.js.map