Adding a Robot = One JSON File, Zero Code
The platform's value in one sentence: "Any robot runs in simulation from a single manifest." If adding a new robot requires code changes, that's not a platform — it's a one-off demo.
One Schema, Seven Categories
Manipulator arms, quadruped robots, AMRs, drones — all expressed through the same manifest schema. The category field determines the robot type; type-specific blocks (arm spec, leg spec, drone spec, etc.) are swapped in as needed.
Rendering diagram…
- Common fields: name, asset (USD/URDF) path, kinematics (radius, wheelbase), sensor list, etc.
- Type-specific block: joints and gripper for an arm; gait policy for a legged robot; steering and drive mode for a vehicle.
Here is the same promise on screen. The three clips below share the same task (pick and place), the same environment, and the same camera settings. The only thing that changed is the arm the manifest points at — not one line of scoring code was touched.
▶ Techman TM12 with a Robotiq gripper — finishes the task in 12 seconds.
▶ Universal Robots UR10 with a Robotiq gripper — same task, same scorer. 26.8 seconds.
▶ Franka Panda — finishes in 4.8 seconds. The spread in completion time comes from each arm's kinematics, not from the platform.
Completion times spread more than fivefold, from 4.8 to 26.8 seconds. That spread comes from each arm's joint layout and reach path; the simulator, the scorer and the scenario are identical across all three. What changed was one JSON file.
Thanks to this unified abstraction, selecting "this robot" from the catalog causes the simulator to read its manifest and spawn it directly — no divergent code paths per robot type.
A manifest looks roughly like this — one human-readable, human-writable JSON file.
{
"name": "warehouse_amr_01",
"category": "AMR",
"asset": "robots/amr_01/amr_01.usd",
"kinematics": { "drive": "differential", "radius_m": 0.30, "wheel_base_m": 0.45 },
"sensors": ["lidar_2d", "imu", "camera_front"]
}
Onboarding Has Four Difficulty Levels
Not every robot is equally easy to add. The difficulty is determined not by lines of code but by whether existing handlers can be reused.
| Type | Example | Work required |
|---|---|---|
| A | New robot with an existing locomotion type | Manifest only (hours) |
| B | Unusual sensor configuration | Manifest + sensor setup |
| C | New locomotion type (omni-wheel, holonomic) | Handler extension required |
| D | Compound robot (arm + mobile base) | Days |
💡 Most robots are type A — one manifest JSON file, and that's it. Code changes are only needed when a genuinely new locomotion type (e.g., omni-wheel) appears for the first time.
Where the Promise Leaks — Honest Accounting
"Zero code" is the goal; in practice there are gaps.
⚠️ Cases exist where a single-arm adapter silently fails for robots other than the one it was written for, manifest schema keys are hard-coded in tooling, or compound robots (arm + gripper) require special handling. The platform promise depends on how honestly the adapter layer abstracts away differences — closing those gaps is the work of growing the platform.
This manifest, alongside other data contracts like RuntimeConfig and specs_json seen elsewhere in the codebase, is one pillar of the design philosophy: "express intent in the domain language."
In a nutshell
📌 Any robot is added via a single manifest (JSON) —
categorydetermines the type and the type-specific block is swapped in, a single abstraction for all. Most robots require zero code changes (type A); handler extension is only needed for genuinely new locomotion types. The promise depends on the honesty of the adapter layer.
References
See standard test results with videos and verdict evidence on the imSim Portal.
View public results →