Getting Started

This guide will help you get started with the MIMIC Scene Edition API.

Installation

You write scene edits against the client SDK, qvyon-mimic-sdk (imported as mimic_sdk). Your script records an op-list; MIMIC replays it and renders the result. Nothing executes locally, so the SDK needs no GPU, no scene data and no checkout of this repository — only the standard library.

The standalone package

The SDK ships as one zip holding the wheel, ten worked examples, this documentation and a VS Code project:

qvyon-mimic-sdk-standalone-<version>.zip
├── wheel/qvyon_mimic_sdk-<version>-py3-none-any.whl
├── examples/s01_ego_lane_offset.py …
├── docs/index.html
├── pyproject.toml
└── .vscode/

Unzip it and run an example. uv fetches a Python interpreter, installs the wheel from wheel/ and runs the script — that is the whole setup:

uv run examples/s01_ego_lane_offset.py

In VS Code, open the folder, run uv sync once, then press F5. The debug list holds every example by name, and justMyCode is off, so a breakpoint inside scene.ego.shift(...) hits.

To install the wheel into an environment you already have (any Python ≥ 3.10):

pip install wheel/qvyon_mimic_sdk-<version>-py3-none-any.whl

What a script looks like

from mimic_sdk.scene_edition import MimicSceneEditor

client = MimicSceneEditor.login()                  # resolves the local store
scene = client.open_scene(sequence_id="lane_occlusion")

with scene.generate_variant("truck_at_45") as variant:
    variant.ego.shift(left=1.0)
    truck = variant.insert_static_actor(
        actor_id="actor_10021", at_idx=60, yaw=45.0
    )
    variant.actor(truck).shift(forward=3.0)

print(client.document_path())
client.submit_variant("truck_at_45")               # one variant, ops inline

Every method call appends an op; leaving the block cleanly saves the variant to ~/.mimic/variants/<sequence_id>/<script_id>.variant.json. A block that raises writes nothing, and each variant is a fork of the baseline rather than a continuation of the previous one.

Building the package

Maintainers regenerate the zip from the current op catalog with:

moon run mimic-scene-edition:package-sdk   # or: tools/package_standalone_sdk.sh
# → build/dist/qvyon-mimic-sdk-standalone-<version>.zip

Working on this library

mimic-scene-edition itself is the server-side library that executes op-lists. It pins Python 3.10 (requires-python = ">=3.10,<3.11") because of its native dependencies, which is exactly why the client SDK is a separate, pure-stdlib package. From a clone of the repository:

uv sync                 # add --all-groups for dev + docs extras
uv pip install -e .
uv run pytest -v

The recorder/decoder fidelity report doubles as the CI gate for the op-list lane and is also installed as the mimic-oplist-verify command:

uv run python -m mimic_scene_edition.oplist.verify
uv run python -m mimic_scene_edition.oplist.verify s01 s10   # narrow to a few

Basic Concepts

Coordinate Frames

The API uses two coordinate frames:

Local (Vehicle) Frame: - X: Forward - Y: Left - Z: Up

World Frame: - Fixed global coordinates - Scene-dependent orientation

Most methods accept a referential parameter to specify which frame to use.

Fluent Interface

All editor methods return self, enabling method chaining:

scene.ego.shift(forward=5).rotate(yaw=15).stop(at_idx=50)

This is equivalent to:

scene.ego.shift(forward=5)
scene.ego.rotate(yaw=15)
scene.ego.stop(at_idx=50)

Value Limits

When limited_mode=True, transformation parameters are constrained to prevent extreme edits. This is useful for generating realistic variations. See Limits for the default allowed ranges per parameter.

Editor Hierarchy

SceneEditor (scene)
├── ego → EgoEditor
│   └── Manages ego trajectory and sensor rig
├── actor(id) → ActorEditor
│   └── Manages individual actor trajectories
├── camera(ref) → SensorEditor
├── lidar(ref) → SensorEditor
└── radar(ref) → SensorEditor

Common Operations

Ego Vehicle

# Move ego forward
scene.ego.shift(forward=5)

# Rotate ego
scene.ego.rotate(yaw=15)

# Stop ego at frame 50
scene.ego.stop(at_idx=50)

# Change speed
scene.ego.speed(multiplier=0.8)

# Lane change maneuver
scene.ego.smooth_lane_change(
    start_idx=20,
    duration=40,
    left=3.5
)

Actors

# Get actor editor
actor = scene.actor(4)

# Displace along path
actor.displace(forward=20)

# Shift laterally (change lanes)
actor.shift(left=3.5)

# Rotate
actor.rotate(yaw=90)

# Stop actor
actor.stop(at_idx=30)

# Change speed
actor.speed(multiplier=1.5)

Sensors

# Access by name
cam = scene.camera("FRONT")

# Shift sensor position
cam.shift(up=0.05, forward=0.1)

# Rotate sensor
cam.rotate(pitch=-2)

# Scale resolution
cam.scale_camera_resolution(scale=0.5)

# Set intrinsics
cam.set_camera_intrinsics(fx=1000, fy=1000, cx=960, cy=540)

Inserting Actors

# Insert actor on ego trajectory
new_id = scene.insert_actor_on_ego_trajectory(
    4,  # source actor ID
    forward=30,
    left=3.5
)

# Insert static actor
new_id = scene.insert_static_actor(
    4,
    at_idx=0,
    forward=20,
    yaw=90
)

# Create crossing pedestrian
new_id = scene.crossing(
    pedestrian_id,
    start=20,
    end=60,
    forward=15,
    direction="right_to_left"
)

AutoSplat Runtime Toggles

Mute or restore the AutoSplat per-frame appearance residual (brake lights, blinkers, and other dynamic overlays). These methods only take visible effect inside the render pipeline; in a pure offline editor the call is recorded in editions but is otherwise a no-op.

# Mute the appearance residual for the whole scene
scene.object_appearance(False)

# Re-enable it for a single actor
scene.actor(28).object_appearance(True)

Debugging

All modifications are tracked:

# Get list of all edits
mods = scene.get_modifications()

for mod in mods:
    print(f"{mod['method']}: {mod['description']}")

Reset to original state:

scene.reset()