mujoco-react 9.0.0 → 9.1.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/README.md +17 -0
- package/dist/index.d.ts +3 -31
- package/dist/index.js +135 -114
- package/dist/index.js.map +1 -1
- package/dist/spark.d.ts +1 -1
- package/dist/{types-izZlUweI.d.ts → types-C5gTvR7b.d.ts} +32 -1
- package/package.json +1 -1
- package/src/core/MujocoSimProvider.tsx +27 -1
- package/src/hooks/useFrameCapture.ts +8 -42
- package/src/index.ts +8 -9
- package/src/types.ts +46 -0
package/README.md
CHANGED
|
@@ -983,6 +983,20 @@ const video = useVideoRecorder({ fps: 30, mimeType: "video/webm" });
|
|
|
983
983
|
// video.start(), video.stop() -> returns Blob
|
|
984
984
|
```
|
|
985
985
|
|
|
986
|
+
### Frame Capture
|
|
987
|
+
|
|
988
|
+
Capture dataset/debug stills from the rendered MuJoCo canvas:
|
|
989
|
+
|
|
990
|
+
```tsx
|
|
991
|
+
const apiRef = useRef<MujocoSimAPI>(null);
|
|
992
|
+
|
|
993
|
+
const frame = await apiRef.current?.captureFrame({ type: "image/png" });
|
|
994
|
+
const blob = await apiRef.current?.captureFrameBlob({ type: "image/png" });
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
Use `useFrameCapture()` or the standalone `captureFrame()` helpers when you own
|
|
998
|
+
the canvas or want to capture a custom container.
|
|
999
|
+
|
|
986
1000
|
### `useCtrlNoise(config)`
|
|
987
1001
|
|
|
988
1002
|
Apply Gaussian noise to controls for robustness testing:
|
|
@@ -1104,7 +1118,10 @@ The full API object available via `ref` or `useMujoco()` (when `isReady`):
|
|
|
1104
1118
|
|--------|-------------|
|
|
1105
1119
|
| `raycast(origin, direction, maxDist?)` | Physics raycast via `mj_ray` |
|
|
1106
1120
|
| `project2DTo3D(x, y, camPos, lookAt)` | Screen-to-world raycast (returns bodyId + geomId) |
|
|
1121
|
+
| `getCanvas()` | Return the underlying R3F canvas element |
|
|
1107
1122
|
| `getCanvasSnapshot(w?, h?, mime?)` | Base64 screenshot |
|
|
1123
|
+
| `captureFrame(options?)` | Capture the canvas as a data URL |
|
|
1124
|
+
| `captureFrameBlob(options?)` | Capture the canvas as a Blob |
|
|
1108
1125
|
|
|
1109
1126
|
### Scene Management
|
|
1110
1127
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { M as MujocoContextValue, a as MujocoCanvasProps, b as MujocoSimAPI, S as SceneConfig, R as ReadyCallbackInput, c as StepCallbackInput, d as SelectionCallbackInput, e as MujocoModule, P as PhysicsStepCallback, f as MujocoModel, g as MujocoData, C as ControlGroupInfo, A as ActuatedJointInfo, h as ControlGroupSelector, O as ObservationConfig, i as ObservationResult, I as IkConfig, j as IkContextValue, B as BodyProps, k as IkGizmoProps, D as DragInteractionProps, l as SceneLightsProps, m as ScenarioLightingProps, n as SplatEnvironmentProps, V as VisualScenarioEffectsProps, o as VisualScenarioConfig, p as SplatRendererKind, q as PairedSplatEnvironmentConfig, r as SplatFormat, s as SplatCollisionProxyConfig, t as SplatCollisionPrimitive, u as ScenarioLightingPreset, v as SplatEnvironmentMetadataInput, w as SplatEnvironmentMetadata, x as SplatSceneInput, y as DebugProps, G as GeomInfo, z as ContactListenerProps, T as TrajectoryPlayerProps, E as ActuatorInfo, F as Sites, H as SitePositionResult, J as Sensors, K as SensorHandle, L as SensorInfo, N as Joints, Q as JointStateResult, U as Bodies, W as BodyStateResult, X as Actuators, Y as CtrlHandle, Z as ContactInfo, _ as KeyboardTeleopConfig, $ as PolicyConfig, a0 as PolicyVector, a1 as ObservationHandle, a2 as TrajectoryInput, a3 as TrajectoryStateChangeInput, a4 as PlaybackState, a5 as TrajectoryFrame } from './types-
|
|
3
|
-
export {
|
|
2
|
+
import { M as MujocoContextValue, a as MujocoCanvasProps, b as MujocoSimAPI, S as SceneConfig, R as ReadyCallbackInput, c as StepCallbackInput, d as SelectionCallbackInput, e as MujocoModule, P as PhysicsStepCallback, f as MujocoModel, g as MujocoData, C as ControlGroupInfo, A as ActuatedJointInfo, h as ControlGroupSelector, O as ObservationConfig, i as ObservationResult, I as IkConfig, j as IkContextValue, B as BodyProps, k as IkGizmoProps, D as DragInteractionProps, l as SceneLightsProps, m as ScenarioLightingProps, n as SplatEnvironmentProps, V as VisualScenarioEffectsProps, o as VisualScenarioConfig, p as SplatRendererKind, q as PairedSplatEnvironmentConfig, r as SplatFormat, s as SplatCollisionProxyConfig, t as SplatCollisionPrimitive, u as ScenarioLightingPreset, v as SplatEnvironmentMetadataInput, w as SplatEnvironmentMetadata, x as SplatSceneInput, y as DebugProps, G as GeomInfo, z as ContactListenerProps, T as TrajectoryPlayerProps, E as ActuatorInfo, F as Sites, H as SitePositionResult, J as Sensors, K as SensorHandle, L as SensorInfo, N as Joints, Q as JointStateResult, U as Bodies, W as BodyStateResult, X as Actuators, Y as CtrlHandle, Z as ContactInfo, _ as KeyboardTeleopConfig, $ as PolicyConfig, a0 as PolicyVector, a1 as ObservationHandle, a2 as TrajectoryInput, a3 as TrajectoryStateChangeInput, a4 as PlaybackState, a5 as TrajectoryFrame, a6 as FrameCaptureOptions, a7 as FrameCaptureResult, a8 as FrameCaptureBlobResult, a9 as FrameCaptureAPI } from './types-C5gTvR7b.js';
|
|
3
|
+
export { aa as BodyInfo, ab as ControlJointInfo, ac as FrameCaptureStatus, ad as FrameCaptureTarget, ae as FrameCaptureTargetRef, af as Geoms, ag as IKSolveFn, ah as IkGizmoDragInput, ai as IkSolveInput, aj as JointInfo, ak as KeyBinding, al as Keyframes, am as ModelOptions, an as MujocoContact, ao as MujocoContactArray, ap as MujocoFrameCaptureOptions, aq as ObservationLayoutItem, ar as ObservationOutput, as as PhysicsConfig, at as PhysicsStepInput, au as PolicyActionInput, av as PolicyInferenceInput, aw as PolicyObservationInput, ax as RayHit, ay as Register, az as RegisteredRobotMap, aA as ResetCallbackInput, aB as ResourceSelector, aC as RobotActuators, aD as RobotBodies, aE as RobotGeoms, aF as RobotJoints, aG as RobotKeyframes, aH as RobotResource, aI as RobotResources, aJ as RobotSensors, aK as RobotSites, aL as Robots, aM as ScenarioCameraConfig, aN as ScenarioMaterialConfig, aO as SceneMarker, aP as SceneObject, aQ as SensorResult, aR as SiteInfo, aS as SplatAssetConfig, aT as SplatScenarioConfig, aU as StateSnapshot, aV as TrajectoryData, aW as TrajectoryFrameCallbackInput, aX as VisualScenarioMaterialFilterInput, aY as XmlPatch, aZ as getContact, a_ as registerRobotResources } from './types-C5gTvR7b.js';
|
|
4
4
|
import * as React$1 from 'react';
|
|
5
|
-
import React__default from 'react';
|
|
6
5
|
import { ThreeElements } from '@react-three/fiber';
|
|
7
6
|
import * as THREE from 'three';
|
|
8
7
|
|
|
@@ -758,33 +757,6 @@ declare function useVideoRecorder(options?: VideoRecorderOptions): {
|
|
|
758
757
|
* useFrameCapture — still-frame capture for canvas-backed MuJoCo/R3F scenes.
|
|
759
758
|
*/
|
|
760
759
|
|
|
761
|
-
type FrameCaptureStatus = 'idle' | 'capturing' | 'captured' | 'error';
|
|
762
|
-
type FrameCaptureTarget = HTMLCanvasElement | HTMLElement | null | undefined;
|
|
763
|
-
type FrameCaptureTargetRef = React__default.RefObject<HTMLCanvasElement | HTMLElement | null>;
|
|
764
|
-
interface FrameCaptureOptions {
|
|
765
|
-
target?: FrameCaptureTarget | FrameCaptureTargetRef;
|
|
766
|
-
type?: string;
|
|
767
|
-
quality?: number;
|
|
768
|
-
waitForAnimationFrame?: boolean;
|
|
769
|
-
}
|
|
770
|
-
interface FrameCaptureResult {
|
|
771
|
-
canvas: HTMLCanvasElement;
|
|
772
|
-
dataUrl: string;
|
|
773
|
-
type: string;
|
|
774
|
-
}
|
|
775
|
-
interface FrameCaptureBlobResult {
|
|
776
|
-
canvas: HTMLCanvasElement;
|
|
777
|
-
blob: Blob;
|
|
778
|
-
type: string;
|
|
779
|
-
}
|
|
780
|
-
interface FrameCaptureAPI {
|
|
781
|
-
status: FrameCaptureStatus;
|
|
782
|
-
error: Error | null;
|
|
783
|
-
isCapturing: boolean;
|
|
784
|
-
capture: (options?: FrameCaptureOptions) => Promise<FrameCaptureResult>;
|
|
785
|
-
captureBlob: (options?: FrameCaptureOptions) => Promise<FrameCaptureBlobResult>;
|
|
786
|
-
reset: () => void;
|
|
787
|
-
}
|
|
788
760
|
/**
|
|
789
761
|
* Capture the current canvas frame as a data URL.
|
|
790
762
|
*
|
|
@@ -896,4 +868,4 @@ interface CameraAnimationAPI {
|
|
|
896
868
|
*/
|
|
897
869
|
declare function useCameraAnimation(): CameraAnimationAPI;
|
|
898
870
|
|
|
899
|
-
export { ActuatedJointInfo, ActuatorInfo, Actuators, Bodies, Body, BodyProps, BodyStateResult, type CameraAnimationAPI, ContactInfo, ContactListener, ContactListenerProps, ContactMarkers, ControlGroupInfo, ControlGroupSelector, type ControllerComponent, type ControllerOptions, CtrlHandle, Debug, DebugProps, DragInteraction, DragInteractionProps, FlexRenderer,
|
|
871
|
+
export { ActuatedJointInfo, ActuatorInfo, Actuators, Bodies, Body, BodyProps, BodyStateResult, type CameraAnimationAPI, ContactInfo, ContactListener, ContactListenerProps, ContactMarkers, ControlGroupInfo, ControlGroupSelector, type ControllerComponent, type ControllerOptions, CtrlHandle, Debug, DebugProps, DragInteraction, DragInteractionProps, FlexRenderer, FrameCaptureAPI, FrameCaptureBlobResult, FrameCaptureOptions, FrameCaptureResult, GeomInfo, IkConfig, IkContextValue, IkGizmo, IkGizmoProps, InstancedGeomRenderer, JointStateResult, Joints, KeyboardTeleopConfig, MujocoCanvas, MujocoCanvasProps, MujocoContextValue, MujocoData, type MujocoLoader, type MujocoLoaderOptions, MujocoModel, MujocoModule, MujocoPhysics, type MujocoPhysicsProps, MujocoProvider, type MujocoProviderProps, MujocoSimAPI, MujocoSimProvider, type MujocoWasmVariant, ObservationConfig, ObservationHandle, ObservationResult, PairedSplatEnvironmentConfig, PhysicsStepCallback, PlaybackState, PolicyConfig, PolicyVector, ReadyCallbackInput, ScenarioLighting, ScenarioLightingPreset, ScenarioLightingProps, SceneConfig, SceneLights, SceneLightsProps, SelectionCallbackInput, SensorHandle, SensorInfo, Sensors, SitePositionResult, Sites, SplatCollisionPrimitive, SplatCollisionProxyConfig, SplatEnvironment, SplatEnvironmentMetadata, SplatEnvironmentMetadataInput, SplatEnvironmentProps, SplatFormat, SplatRendererKind, SplatSceneInput, StepCallbackInput, TendonRenderer, TrajectoryFrame, TrajectoryInput, TrajectoryPlayer, TrajectoryPlayerProps, TrajectoryStateChangeInput, VisualScenarioConfig, VisualScenarioEffects, VisualScenarioEffectsProps, buildObservation, captureFrame, captureFrameBlob, createContiguousControlGroup, createController, createControllerHook, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getControlMap, getName, getScenarioBackground, getScenarioCameraPosition, loadScene, 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, useSplatEnvironment, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder, useVisualScenarioEffects, withSplatEnvironment };
|
package/dist/index.js
CHANGED
|
@@ -1294,6 +1294,114 @@ function SceneRenderer(props) {
|
|
|
1294
1294
|
}
|
|
1295
1295
|
var _previousQuat = new THREE11.Quaternion();
|
|
1296
1296
|
var _currentQuat = new THREE11.Quaternion();
|
|
1297
|
+
function isTargetRef(target) {
|
|
1298
|
+
return Boolean(target && typeof target === "object" && "current" in target);
|
|
1299
|
+
}
|
|
1300
|
+
function resolveCanvasTarget(target) {
|
|
1301
|
+
const resolvedTarget = isTargetRef(target) ? target.current : target;
|
|
1302
|
+
if (!resolvedTarget) {
|
|
1303
|
+
throw new Error("No frame capture target is available.");
|
|
1304
|
+
}
|
|
1305
|
+
if (resolvedTarget instanceof HTMLCanvasElement) {
|
|
1306
|
+
return resolvedTarget;
|
|
1307
|
+
}
|
|
1308
|
+
const canvas = resolvedTarget.querySelector("canvas");
|
|
1309
|
+
if (!canvas) {
|
|
1310
|
+
throw new Error("Frame capture target does not contain a canvas.");
|
|
1311
|
+
}
|
|
1312
|
+
return canvas;
|
|
1313
|
+
}
|
|
1314
|
+
function waitForNextAnimationFrame() {
|
|
1315
|
+
return new Promise((resolve) => {
|
|
1316
|
+
requestAnimationFrame(() => resolve());
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
async function captureFrame(options) {
|
|
1320
|
+
const type = options.type ?? "image/png";
|
|
1321
|
+
const canvas = resolveCanvasTarget(options.target);
|
|
1322
|
+
if (options.waitForAnimationFrame ?? true) {
|
|
1323
|
+
await waitForNextAnimationFrame();
|
|
1324
|
+
}
|
|
1325
|
+
return {
|
|
1326
|
+
canvas,
|
|
1327
|
+
dataUrl: canvas.toDataURL(type, options.quality),
|
|
1328
|
+
type
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
async function captureFrameBlob(options) {
|
|
1332
|
+
const type = options.type ?? "image/png";
|
|
1333
|
+
const canvas = resolveCanvasTarget(options.target);
|
|
1334
|
+
if (options.waitForAnimationFrame ?? true) {
|
|
1335
|
+
await waitForNextAnimationFrame();
|
|
1336
|
+
}
|
|
1337
|
+
const blob = await new Promise((resolve, reject) => {
|
|
1338
|
+
canvas.toBlob(
|
|
1339
|
+
(nextBlob) => {
|
|
1340
|
+
if (nextBlob) {
|
|
1341
|
+
resolve(nextBlob);
|
|
1342
|
+
} else {
|
|
1343
|
+
reject(new Error("Canvas frame capture did not produce a Blob."));
|
|
1344
|
+
}
|
|
1345
|
+
},
|
|
1346
|
+
type,
|
|
1347
|
+
options.quality
|
|
1348
|
+
);
|
|
1349
|
+
});
|
|
1350
|
+
return { canvas, blob, type };
|
|
1351
|
+
}
|
|
1352
|
+
function useFrameCapture(defaultOptions = {}) {
|
|
1353
|
+
const [status, setStatus] = useState("idle");
|
|
1354
|
+
const [error, setError] = useState(null);
|
|
1355
|
+
const reset = useCallback(() => {
|
|
1356
|
+
setStatus("idle");
|
|
1357
|
+
setError(null);
|
|
1358
|
+
}, []);
|
|
1359
|
+
const capture = useCallback(
|
|
1360
|
+
async (options = {}) => {
|
|
1361
|
+
setStatus("capturing");
|
|
1362
|
+
setError(null);
|
|
1363
|
+
try {
|
|
1364
|
+
const result = await captureFrame({ ...defaultOptions, ...options });
|
|
1365
|
+
setStatus("captured");
|
|
1366
|
+
return result;
|
|
1367
|
+
} catch (nextError) {
|
|
1368
|
+
const error2 = nextError instanceof Error ? nextError : new Error("Unable to capture the current canvas frame.");
|
|
1369
|
+
setError(error2);
|
|
1370
|
+
setStatus("error");
|
|
1371
|
+
throw error2;
|
|
1372
|
+
}
|
|
1373
|
+
},
|
|
1374
|
+
[defaultOptions]
|
|
1375
|
+
);
|
|
1376
|
+
const captureBlob = useCallback(
|
|
1377
|
+
async (options = {}) => {
|
|
1378
|
+
setStatus("capturing");
|
|
1379
|
+
setError(null);
|
|
1380
|
+
try {
|
|
1381
|
+
const result = await captureFrameBlob({
|
|
1382
|
+
...defaultOptions,
|
|
1383
|
+
...options
|
|
1384
|
+
});
|
|
1385
|
+
setStatus("captured");
|
|
1386
|
+
return result;
|
|
1387
|
+
} catch (nextError) {
|
|
1388
|
+
const error2 = nextError instanceof Error ? nextError : new Error("Unable to capture the current canvas frame.");
|
|
1389
|
+
setError(error2);
|
|
1390
|
+
setStatus("error");
|
|
1391
|
+
throw error2;
|
|
1392
|
+
}
|
|
1393
|
+
},
|
|
1394
|
+
[defaultOptions]
|
|
1395
|
+
);
|
|
1396
|
+
return {
|
|
1397
|
+
status,
|
|
1398
|
+
error,
|
|
1399
|
+
isCapturing: status === "capturing",
|
|
1400
|
+
capture,
|
|
1401
|
+
captureBlob,
|
|
1402
|
+
reset
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1297
1405
|
var JOINT_TYPE_NAMES2 = ["free", "ball", "slide", "hinge"];
|
|
1298
1406
|
var GEOM_TYPE_NAMES = ["plane", "hfield", "sphere", "capsule", "ellipsoid", "cylinder", "box", "mesh"];
|
|
1299
1407
|
var SENSOR_TYPE_NAMES = {
|
|
@@ -2145,6 +2253,21 @@ function MujocoSimProvider({
|
|
|
2145
2253
|
},
|
|
2146
2254
|
[gl]
|
|
2147
2255
|
);
|
|
2256
|
+
const getCanvas = useCallback(() => {
|
|
2257
|
+
return gl.domElement ?? null;
|
|
2258
|
+
}, [gl]);
|
|
2259
|
+
const captureFrameApi = useCallback(
|
|
2260
|
+
(options = {}) => {
|
|
2261
|
+
return captureFrame({ ...options, target: gl.domElement });
|
|
2262
|
+
},
|
|
2263
|
+
[gl]
|
|
2264
|
+
);
|
|
2265
|
+
const captureFrameBlobApi = useCallback(
|
|
2266
|
+
(options = {}) => {
|
|
2267
|
+
return captureFrameBlob({ ...options, target: gl.domElement });
|
|
2268
|
+
},
|
|
2269
|
+
[gl]
|
|
2270
|
+
);
|
|
2148
2271
|
const project2DTo3D = useCallback(
|
|
2149
2272
|
(x, y, cameraPos, lookAt) => {
|
|
2150
2273
|
const virtCam = camera.clone();
|
|
@@ -2251,7 +2374,10 @@ function MujocoSimProvider({
|
|
|
2251
2374
|
addBody: addBodyApi,
|
|
2252
2375
|
removeBody: removeBodyApi,
|
|
2253
2376
|
recompile: recompileApi,
|
|
2377
|
+
getCanvas,
|
|
2254
2378
|
getCanvasSnapshot,
|
|
2379
|
+
captureFrame: captureFrameApi,
|
|
2380
|
+
captureFrameBlob: captureFrameBlobApi,
|
|
2255
2381
|
project2DTo3D,
|
|
2256
2382
|
setBodyMass,
|
|
2257
2383
|
setGeomFriction,
|
|
@@ -2303,7 +2429,10 @@ function MujocoSimProvider({
|
|
|
2303
2429
|
addBodyApi,
|
|
2304
2430
|
removeBodyApi,
|
|
2305
2431
|
recompileApi,
|
|
2432
|
+
getCanvas,
|
|
2306
2433
|
getCanvasSnapshot,
|
|
2434
|
+
captureFrameApi,
|
|
2435
|
+
captureFrameBlobApi,
|
|
2307
2436
|
project2DTo3D,
|
|
2308
2437
|
setBodyMass,
|
|
2309
2438
|
setGeomFriction,
|
|
@@ -4979,114 +5108,6 @@ function useVideoRecorder(options = {}) {
|
|
|
4979
5108
|
}
|
|
4980
5109
|
};
|
|
4981
5110
|
}
|
|
4982
|
-
function isTargetRef(target) {
|
|
4983
|
-
return Boolean(target && typeof target === "object" && "current" in target);
|
|
4984
|
-
}
|
|
4985
|
-
function resolveCanvasTarget(target) {
|
|
4986
|
-
const resolvedTarget = isTargetRef(target) ? target.current : target;
|
|
4987
|
-
if (!resolvedTarget) {
|
|
4988
|
-
throw new Error("No frame capture target is available.");
|
|
4989
|
-
}
|
|
4990
|
-
if (resolvedTarget instanceof HTMLCanvasElement) {
|
|
4991
|
-
return resolvedTarget;
|
|
4992
|
-
}
|
|
4993
|
-
const canvas = resolvedTarget.querySelector("canvas");
|
|
4994
|
-
if (!canvas) {
|
|
4995
|
-
throw new Error("Frame capture target does not contain a canvas.");
|
|
4996
|
-
}
|
|
4997
|
-
return canvas;
|
|
4998
|
-
}
|
|
4999
|
-
function waitForNextAnimationFrame() {
|
|
5000
|
-
return new Promise((resolve) => {
|
|
5001
|
-
requestAnimationFrame(() => resolve());
|
|
5002
|
-
});
|
|
5003
|
-
}
|
|
5004
|
-
async function captureFrame(options) {
|
|
5005
|
-
const type = options.type ?? "image/png";
|
|
5006
|
-
const canvas = resolveCanvasTarget(options.target);
|
|
5007
|
-
if (options.waitForAnimationFrame ?? true) {
|
|
5008
|
-
await waitForNextAnimationFrame();
|
|
5009
|
-
}
|
|
5010
|
-
return {
|
|
5011
|
-
canvas,
|
|
5012
|
-
dataUrl: canvas.toDataURL(type, options.quality),
|
|
5013
|
-
type
|
|
5014
|
-
};
|
|
5015
|
-
}
|
|
5016
|
-
async function captureFrameBlob(options) {
|
|
5017
|
-
const type = options.type ?? "image/png";
|
|
5018
|
-
const canvas = resolveCanvasTarget(options.target);
|
|
5019
|
-
if (options.waitForAnimationFrame ?? true) {
|
|
5020
|
-
await waitForNextAnimationFrame();
|
|
5021
|
-
}
|
|
5022
|
-
const blob = await new Promise((resolve, reject) => {
|
|
5023
|
-
canvas.toBlob(
|
|
5024
|
-
(nextBlob) => {
|
|
5025
|
-
if (nextBlob) {
|
|
5026
|
-
resolve(nextBlob);
|
|
5027
|
-
} else {
|
|
5028
|
-
reject(new Error("Canvas frame capture did not produce a Blob."));
|
|
5029
|
-
}
|
|
5030
|
-
},
|
|
5031
|
-
type,
|
|
5032
|
-
options.quality
|
|
5033
|
-
);
|
|
5034
|
-
});
|
|
5035
|
-
return { canvas, blob, type };
|
|
5036
|
-
}
|
|
5037
|
-
function useFrameCapture(defaultOptions = {}) {
|
|
5038
|
-
const [status, setStatus] = useState("idle");
|
|
5039
|
-
const [error, setError] = useState(null);
|
|
5040
|
-
const reset = useCallback(() => {
|
|
5041
|
-
setStatus("idle");
|
|
5042
|
-
setError(null);
|
|
5043
|
-
}, []);
|
|
5044
|
-
const capture = useCallback(
|
|
5045
|
-
async (options = {}) => {
|
|
5046
|
-
setStatus("capturing");
|
|
5047
|
-
setError(null);
|
|
5048
|
-
try {
|
|
5049
|
-
const result = await captureFrame({ ...defaultOptions, ...options });
|
|
5050
|
-
setStatus("captured");
|
|
5051
|
-
return result;
|
|
5052
|
-
} catch (nextError) {
|
|
5053
|
-
const error2 = nextError instanceof Error ? nextError : new Error("Unable to capture the current canvas frame.");
|
|
5054
|
-
setError(error2);
|
|
5055
|
-
setStatus("error");
|
|
5056
|
-
throw error2;
|
|
5057
|
-
}
|
|
5058
|
-
},
|
|
5059
|
-
[defaultOptions]
|
|
5060
|
-
);
|
|
5061
|
-
const captureBlob = useCallback(
|
|
5062
|
-
async (options = {}) => {
|
|
5063
|
-
setStatus("capturing");
|
|
5064
|
-
setError(null);
|
|
5065
|
-
try {
|
|
5066
|
-
const result = await captureFrameBlob({
|
|
5067
|
-
...defaultOptions,
|
|
5068
|
-
...options
|
|
5069
|
-
});
|
|
5070
|
-
setStatus("captured");
|
|
5071
|
-
return result;
|
|
5072
|
-
} catch (nextError) {
|
|
5073
|
-
const error2 = nextError instanceof Error ? nextError : new Error("Unable to capture the current canvas frame.");
|
|
5074
|
-
setError(error2);
|
|
5075
|
-
setStatus("error");
|
|
5076
|
-
throw error2;
|
|
5077
|
-
}
|
|
5078
|
-
},
|
|
5079
|
-
[defaultOptions]
|
|
5080
|
-
);
|
|
5081
|
-
return {
|
|
5082
|
-
status,
|
|
5083
|
-
error,
|
|
5084
|
-
isCapturing: status === "capturing",
|
|
5085
|
-
capture,
|
|
5086
|
-
captureBlob,
|
|
5087
|
-
reset
|
|
5088
|
-
};
|
|
5089
|
-
}
|
|
5090
5111
|
function useCtrlNoise(config = {}) {
|
|
5091
5112
|
const { mjModelRef } = useMujocoContext();
|
|
5092
5113
|
const configRef = useRef(config);
|
|
@@ -5239,6 +5260,12 @@ function useCameraAnimation() {
|
|
|
5239
5260
|
* @license
|
|
5240
5261
|
* SPDX-License-Identifier: Apache-2.0
|
|
5241
5262
|
*/
|
|
5263
|
+
/**
|
|
5264
|
+
* @license
|
|
5265
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5266
|
+
*
|
|
5267
|
+
* useFrameCapture — still-frame capture for canvas-backed MuJoCo/R3F scenes.
|
|
5268
|
+
*/
|
|
5242
5269
|
/**
|
|
5243
5270
|
* @license
|
|
5244
5271
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -5372,12 +5399,6 @@ function useCameraAnimation() {
|
|
|
5372
5399
|
*
|
|
5373
5400
|
* useVideoRecorder — canvas video recording hook (spec 13.3)
|
|
5374
5401
|
*/
|
|
5375
|
-
/**
|
|
5376
|
-
* @license
|
|
5377
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5378
|
-
*
|
|
5379
|
-
* useFrameCapture — still-frame capture for canvas-backed MuJoCo/R3F scenes.
|
|
5380
|
-
*/
|
|
5381
5402
|
/**
|
|
5382
5403
|
* @license
|
|
5383
5404
|
* SPDX-License-Identifier: Apache-2.0
|