Rendering
Rendering is a post-hoc process, decoupled from JIT-compiled simulation. The typical workflow:
- Run a fast fitness pass to identify good individuals
- Rerun the best with a render-compatible step function to capture positions and spring state
- Convert captured data to GIF frames
RenderConfig
Section titled “RenderConfig”All rendering options are controlled by RenderConfig:
from jax_evogym import RenderConfig
config = RenderConfig( enabled=True, width=600, height=300, fps=50, camera_mode="fit_robot",)| Field | Default | Description |
|---|---|---|
enabled | False | Master switch |
width | 600 | Output pixel width |
height | 300 | Output pixel height |
fps | 50 | Target frame rate |
real_time | True | Match physics timing (auto-computes frame skip) |
frame_skip | 7 | Manual frame skip (used when real_time=False) |
show_grid | False | Draw grid lines |
show_edges | True | Draw surface edges |
dynamic_actuator_colors | True | Color actuators by current actuation level |
camera_padding | 0.3 | World units of padding around robot |
viewport_width | 4.0 | World units visible horizontally |
camera_mode | "fit_robot" | Camera tracking mode |
camera_smoothing | 0.18 | Camera lerp factor (0=instant, 1=static) |
supersample | 2 | Supersampling factor for antialiasing |
output_dir | "renders" | Directory for saved GIFs |
target_frames | None | Optional frame budget cap |
max_colors | 256 | GIF palette size |
optimize | False | GIF frame optimization |
dither | True | Floyd-Steinberg dithering |
Camera modes
Section titled “Camera modes”"fit_robot": viewport expands to fit the robot with padding, never smaller thanviewport_width- Fixed: any other value uses
viewport_widthas-is, centered on robot COM
End-to-end example
Section titled “End-to-end example”import jaximport jax.numpy as jnpimport numpy as npfrom jax_evogym import ( H_ACT, SOFT, V_ACT, WalkerV0, RenderConfig, make_render_episode_step, render_episode, save_gif,)
# 1. Create environmentbody = np.array([[H_ACT, SOFT, V_ACT]])env = WalkerV0(body)obs, init_state = env.reset()
# 2. Run render pass (captures positions + spring state)render_step = make_render_episode_step(env)actions = jnp.ones((500, env.n_actuators))final_state, outputs = jax.lax.scan(render_step, init_state, actions)
# 3. Render and saveconfig = RenderConfig(enabled=True)frames = render_episode(outputs, env.render_info, config)save_gif(frames, "walker.gif", config)Core functions
Section titled “Core functions”make_render_episode_step
Section titled “make_render_episode_step”render_step = make_render_episode_step(env)Returns a lax.scan-compatible step function that captures RenderStepOutput (positions, spring rest lengths, reward, done) at each step. Works with any EvoGymBaseEnv subclass.
render_episode
Section titled “render_episode”frames = render_episode(render_outputs, render_info, config)Converts a batch of RenderStepOutput from lax.scan into a list of PIL Image frames. Handles frame skipping, camera tracking, viewport culling, and dynamic actuator coloring.
render_frame
Section titled “render_frame”img, camera_pos = render_frame(positions_np, render_info, config, ...)Renders a single frame. Lower-level than render_episode — you handle frame iteration yourself. Returns the PIL Image and updated camera position for smooth tracking.
save_gif
Section titled “save_gif”path = save_gif(frames, "output.gif", config)Quantizes frames to a shared palette and saves as animated GIF. Uses config.frame_duration_ms, config.max_colors, config.dither, and config.optimize.
Batch rendering
Section titled “Batch rendering”render_top_k
Section titled “render_top_k”paths = render_top_k( batched_render_outputs, # (n_steps, pop_size, ...) rewards, # (pop_size,) render_info, config, k=3, generation=0,)Renders GIFs for the top-K individuals from a batched evaluation. Expects time-major batched outputs from a vmapped render pass.
rerun_top_k
Section titled “rerun_top_k”paths = rerun_top_k( env, init_state, all_actions, rewards, k=3, config=config, generation=0,)Higher-level: selects top-K by reward, reruns each individually with make_render_episode_step, renders, and saves. Use this when you only have the fitness pass outputs and need to rerun for render data.
Dynamic actuator coloring
Section titled “Dynamic actuator coloring”When dynamic_actuator_colors=True (default), actuator cells are colored by their current spring rest-length ratio relative to the initial rest length:
- Ratio near
0.6(compressed): one end of the gradient - Ratio near
1.6(extended): other end of the gradient H_ACT: cream to burnt orange gradientV_ACT: light blue to dark blue gradientCONTRACTILE: light green to dark green gradient
Non-actuator cells use static colors (RIGID: dark charcoal, SOFT: light gray, FIXED: medium gray).
Static terrain rendering
Section titled “Static terrain rendering”Static terrain (FIXED cells) is rendered from RenderInfo.static_point_positions — true static geometry, not dynamically simulated points. This matches the object-separated architecture where static terrain is excluded from SimState.