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: .. code-block:: text qvyon-mimic-sdk-standalone-.zip ├── wheel/qvyon_mimic_sdk--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: .. code-block:: bash 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): .. code-block:: bash pip install wheel/qvyon_mimic_sdk--py3-none-any.whl What a script looks like ^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: python 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//.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: .. code-block:: bash moon run mimic-scene-edition:package-sdk # or: tools/package_standalone_sdk.sh # → build/dist/qvyon-mimic-sdk-standalone-.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: .. code-block:: bash 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: .. code-block:: bash 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 :doc:`api/limits` for the default allowed ranges per parameter. Editor Hierarchy ---------------- .. code-block:: text 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 ^^^^^^^^^^^ .. code-block:: python # 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 ^^^^^^ .. code-block:: python # 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 ^^^^^^^ .. code-block:: python # 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 ^^^^^^^^^^^^^^^^ .. code-block:: python # 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. .. code-block:: python # 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()