Skip to content

tracer

Tracer dataclass

Python
Tracer(
    target: Traceable,
    duration: float = 1.0,
    color: Vec4 | None = None,
    width: float = 0.005,
    fade: bool = True,
    record_decimation: int = 1,
)

Draws a fading trail of recent world positions behind a Traceable object (a Body, Site, or Geom).

Typical usage inside a runtime function, within a with runtime_manager as rm: block::

Text Only
1
Tracer(target=box1, duration=2.0).register_to_rm()

Sampled once per RuntimeManager.step() and drawn by any VideoRecorder with show_traces=True.

target instance-attribute

Python
target: Traceable

The object whose world position is followed over time.

duration class-attribute instance-attribute

Python
duration: float = 1.0

How many seconds of trailing history to keep.

color class-attribute instance-attribute

Python
color: Vec4 | None = None

RGBA color of the trail. Defaults to the user's visualization.trace_line setting.

width class-attribute instance-attribute

Python
width: float = 0.005

Width of the trail line.

fade class-attribute instance-attribute

Python
fade: bool = True

If True, older segments are drawn more transparent than newer ones.

record_decimation class-attribute instance-attribute

Python
record_decimation: int = 1

How many steps between each recorded point. Increase for long, fine-timestep simulations to reduce the number of trail segments.

update

Python
update(state: MjState) -> None

Records the target's current position, then drops points older than duration. Call once per step.

Source code in src/mujoco_mojo/runtime/tracer.py
Python
def update(self, state: MjState) -> None:
    """Records the target's current position, then drops points older than `duration`. Call once per step."""
    self._step_count += 1
    if self._step_count % self.record_decimation != 0:
        return

    t = state.data.time
    pos = np.array(self.target.rt_pos(state))

    color = self._resolve_color()
    if color is not None and self._history:
        _, prev_pos = self._history[-1]
        self._segments.append(
            LineConfig(
                pos1=prev_pos,
                pos2=pos,
                color=np.array(color, dtype=float),
                width=self.width,
            )
        )
    self._history.append((t, pos))

    cutoff = t - self.duration
    while self._history and self._history[0][0] < cutoff:
        self._history.popleft()
        if self._segments:
            self._segments.popleft()

get_visuals

Python
get_visuals(state: MjState) -> list[LineConfig]

Returns the trail's cached LineConfig segments, one per consecutive pair of recorded positions.

Segments are built once, in update(), as new points are recorded, and reused across every call here - only the fade alpha is refreshed in place, since a segment's position within the trailing window (and therefore its fade level) shifts every step even though its endpoints never change.

Source code in src/mujoco_mojo/runtime/tracer.py
Python
def get_visuals(self, state: MjState) -> list[LineConfig]:
    """
    Returns the trail's cached `LineConfig` segments, one per consecutive pair of recorded positions.

    Segments are built once, in `update()`, as new points are recorded, and reused across every call here - only the fade alpha is refreshed in place, since a segment's position within the trailing window (and therefore its fade level) shifts every step even though its endpoints never change.
    """
    color = self._resolve_color()
    if color is None or not self._segments:
        return []

    if self.fade:
        base_alpha = color[3]
        n = len(self._segments)
        for i, segment in enumerate(self._segments):
            segment.color[3] = base_alpha * (i + 1) / n

    return list(self._segments)