Skip to content

Environment renderings

metrana.log_rendering records reinforcement-learning environment video. Each frame is appended to a per-(env_id, episode) H.264 .mp4, encoded on a dedicated background thread so it never blocks the training loop.

metrana.log_rendering(frame, rl_step, episode, env_id=None)

frame is a uint8 NumPy array:

  • (H, W, 3) — RGB
  • (H, W) or (H, W, 1) — grayscale

Width and height must be even (a libx264 yuv420p requirement).

for t in range(episode_len):
frame = env.render() # uint8 (H, W, 3)
metrana.log_rendering(frame, rl_step=rl_step, episode=episode, env_id="env0")

When the (env_id, episode) pair changes, the open encoder for that env is closed and a new one is opened for the next episode — so each episode of each environment becomes its own MP4. The videos are written under the configured output directory and surface in the portal’s environment views.

Renderings are configured on init():

Argument Default Purpose
rendering_output_dir Where encoded MP4s are written.
rendering_fps 30 Output frame rate.
rendering_max_concurrent_encoders 1 Parallel encoders across (env_id, episode) pairs.
rendering_queue_max_size Bound on the frame queue.
skip_drain_render_on_close False If True, close() drops queued frames instead of encoding them.
rendering_close_timeout How long close() waits to drain queued frames.

Frame-encoding errors are governed by rendering_error_strategy ("silent", "warn" (default), "raise_on_log", "raise_on_close") — this is a separate knob from the engine’s delivery policy. It controls only the Python rendering pipeline; metric/attribute delivery is governed by delivery_policy (see Guarantees & retries).

By default close() drains and encodes any queued frames before returning, bounded by rendering_close_timeout. Frame encoding can lag well behind logging, so this drain can add real time to a close.

If you’d rather not wait on rendering frames at close, set init(skip_drain_render_on_close=True) (or the METRANA_SKIP_DRAIN_RENDER_ON_CLOSE env var). It drops only the queued frames — your metric and attribute delivery still gets close()’s full window, so you skip the video tail without risking metric loss.