Skip to main content
Run a policy inference loop at a fixed frequency, independent of the physics or render rate. usePolicy works with synchronous browser models, remote HTTP policies, and receding-horizon policies that return chunks of future actions. The hook only schedules policy inference and applies the returned actions. It does not run IK, blend actions, or synthesize task logic. If a policy is trained for a scene, the scene, observation vector, camera streams, units, and action order must match that policy.

Signature

Usage

Config

Return Value

How It Works

  1. The hook registers a useBeforePhysicsStep callback
  2. Each physics step, it checks if enough time has elapsed since the last inference (based on frequency)
  3. If a queued action exists, it applies that action with onAction
  4. If inference is needed, it calls onObservation to build the observation vector
  5. Then it calls infer if provided; otherwise it uses the observation as the action
  6. If infer returns a chunk, the first action is applied immediately when possible and the rest are queued
  7. If infer returns a promise, future actions are queued when the promise resolves
For receding-horizon policies, use queueStrategy: "replace" so fresh chunks supersede stale queued actions. Use prefetchThreshold to request the next chunk before the queue is empty. infer receives queuedActions, the number of future actions still buffered when the request starts. Remote policy adapters can pass this to the server so it can tune horizon length, skip work, or report queue telemetry. For long open-loop chunks, use queueStrategy: "append" so prefetching does not discard the tail of the current plan. When pausing a remote policy or changing policy inputs, call reset() or set clearQueueOnStop: true; pending async responses are ignored after a reset so stale server results cannot resume later.

Example: Remote Chunked Policy

useRemotePolicy is a convenience wrapper around usePolicy: it posts JSON to endpoint, accepts responses shaped like { action: number[] } or { actions: number[][] }, and exposes request metadata such as remoteStatus, requestCount, responseCount, lastHttpStatus, and lastRequestMs. It aborts the active HTTP request on stop() and reset() by default; call policy.abort() to cancel explicitly, or set abortOnStop: false to let a request finish in the background. Use parseResponse when a server returns a custom schema. For browser-to-Python inference, an HTTP endpoint that returns chunks is usually enough. WebSockets or SSE are useful when the policy server needs a continuous bidirectional stream, but they add lifecycle complexity that chunked HTTP avoids.

Example: Visual Policy Captures

Pair usePolicy with usePolicyCameraFramesFromMountedStreams when the policy expects images and your camera streams should resolve from the loaded MuJoCo model:
Use capturePolicyCameraFramesFromMountedStreams(api, options) instead when the capture happens outside React.

Example: TensorFlow.js Policy

Notes

  • Disable IK or any other controller that writes the same controls while a policy is running.
  • The policy runs inside useBeforePhysicsStep, so it executes at physics rate but only does inference at frequency Hz
  • onObservation and onAction run in the physics callback; keep them fast.
  • Remote inference belongs in infer, which may return a promise.
  • Match policy units explicitly. For example, do not send degrees to a policy trained on radians.
  • Use applyPolicyActionToControls for the common case of writing an action vector to data.ctrl; it clamps to model.actuator_ctrlrange and skips non-finite entries by default.