Open research in robot manipulation

Tell a robot what to do. Watch it work it out.

Four Claude agents turn one sentence and a depth image into controller skills. The whole stack runs in your browser.

>put the red cube into the box
The Dooms studio mid-run: a Franka Panda arm lifting a bottle, with the plan and controller recipe beside it
94.7%accuracy with Claude planning: 142 of 150 simulated trials solved
5 × 30tasks and random seeds each, no demonstrations
$0.13of Claude calls per task, 8 calls on average
0servers needed to run the simulator

Try the engine. Nothing to install.

MuJoCo compiled to WebAssembly, driving a Franka Panda in a web worker on your machine. The built-in demo planner needs no account.

Planning with Claude? Open the studio and connect either a Claude API key or Amazon Bedrock credentials. Requests go from your browser straight to the provider you choose, and are billed to you.

Open the studio

Four small agents, not one large prompt

Each agent has one job and a typed output. Their answers compile into a stack of task-axis controllers that runs at control rate, with no model in the loop.

keypoints it needs reuse / store 3D points + surface normals subtask failed: look again, then replan grounded skill joint commands A sentence"put the bottle into the box" Camera frameRGB + depth,camera pose Scoutreads the scene,splits the task Composerpicks controllersfor each subtask Tunersets heights,forces, widths Spotterpoints in the image,lifts to 3D Skill libraryrecipes that worked Compilerchecks clearance,orders by priority Controller stacknull-space projection,every control tick The armMuJoCo in WASM,or a real SO-101
Claude agent with a typed outputDeterministic codeMemory that persists between runs

One real run, answer by answer

Everything below is copied from a recorded episode: Claude Sonnet 4.5 on Amazon Bedrock, asked to "put the bottle into the box".

Scout said

The bottle is upright. Six steps.

"The bottle is standing upright on the table to the right of the box. The box appears empty with no obstructions inside. The bottle's cap end is at the top, making it suitable for top-down grasping."

  1. Approach bottle for pre-grasp
  2. Grasp the bottle
  3. Lift the bottle up
  4. Move over the box
  5. Lower the bottle into the box
  6. Release and retract
Composer wrote

A recipe per step, with blanks for the numbers

For the first step it defined a skill called approach_bottle_pregrasp and asked the Spotter for one keypoint, the centre of the bottle's cap.

# subtask 1: Approach bottle for pre-grasp
[p1] PosAlign(eef_tcp, bottle_cap, axis=x, o_x)
[p1] PosAlign(eef_tcp, bottle_cap, axis=y, o_y)
[p1] PosAlign(eef_tcp, bottle_cap, axis=z, o_z)
[p2] AxisAlign(eef_z, bottle_cap_normal, o_theta)
Tuner set

Every blank, with a reason

o_z0.12 mHover 12 cm above the bottle cap for pre-grasp approach
o_theta180°Gripper points down onto upward-facing cap surface
o_d-0.015 mFingertip centre goes half the cap height below the cap top to centre pads on the cap
f3 NGentle contact force threshold for placing the bottle
Spotter pointed

Two pixels become two places in space

The camera frame the Spotter saw, with rings on the bottle cap and inside the box
bottle_cap at pixel 377, 1882.2 mm from the simulator's ground truth
box_inside at pixel 265, 28529 mm off, still inside the tray
The arm did

Bottle in the box, first try

8model calls
$0.13Bedrock cost
6.4 sof robot motion, no replans

It also has to cope when things go wrong

In this recorded run the bottle was knocked over beside the box. The Composer asked for a keypoint that is in no object list, a free spot on the table, and the Spotter found one. A grasp was missed along the way and the scene was grounded again before the run finished.

Camera frame: a bottle lying against the box, with a ring on an empty patch of table
First look: table_free_spot marked bottom left.
Camera frame later in the run: the bottle has moved and is marked again
Later: the bottle has moved, so it is grounded again.

Use it to train models and try out arms

Data

Generate labelled episodes

Every run is seeded and saves the camera frames, 3D keypoints, controller script and a ground-truth success label. That is the raw material for training a manipulation policy.

Models

Compare planners on the same seeds

Swap the Claude model with one flag and read off success rate, cost, latency and grounding error. Ablations turn single stages off.

Arms

Bring up a new arm

An arm is a profile: joints, gripper, workspace. A Franka Panda and an SO-ARM101 ship today, and the SO-101 can be driven for real over USB.

What we are studying

Behaviour as aligned axes, not trajectories

A skill is a short list of controllers, each aligning one point or axis with another, or pushing until contact. The runtime stacks them by priority.

# subtask 5: Lower the bottle into the box
[p1] PosAlign(bottle_cap, box_inside, axis=x, offset=+0.000 m)
[p1] PosAlign(bottle_cap, box_inside, axis=y, offset=+0.000 m)
[p1] Force(axis=-z, contact>=3.0 N)
[p2] AxisAlign(eef_z, box_inside_normal, angle=180 deg)
A yellow SO-ARM101 hobby arm lowering a red cube into a box in the simulator

Two very different arms

A 7-joint Franka Panda and the 5-joint SO-ARM101, which has no force sensor. Same pipeline, a different robot profile.

A skill library that grows

Recipes that succeed are stored by role, not by object name, and offered again with the numbers that worked.

Recovery before replanning

A failed subtask first triggers a second look at the scene. Only if that fails does the Scout plan again from where things now lie.

Inference moved into the browser

The Python stack was ported to TypeScript and a web worker. Claude is called from the page with your own Claude API key or AWS credentials, and skills are kept in IndexedDB. Hosting is static files.

The in-browser 3D view of the Franka arm holding a bottle above the table

94.7% accuracy over 150 trials with Claude

Claude Sonnet 4.5 on Amazon Bedrock plans, a Franka Panda acts. Five tasks, 30 random seeds each, scored by the simulator's own ground truth. Each square is one trial.

SolvedNot solved

No demonstrations and no training: each trial is a fresh plan from one sentence and one camera frame. Accuracy is the share of trials where the object ended up where the task asked: 142 of 150, with a 95% interval of 89.8% to 97.3%. In every miss the arm finished its plan but the object was not in place. Simulation only; nothing here was measured on physical hardware.

What each task cost

TaskAccuracyModel callsCostPlanning timeGrounding error
Put the bottle in the box100% 30 / 308.3$0.13160.3 s12.4 mm
Put the red cube in the box97% 29 / 308.0$0.13361.9 s18.5 mm
Stack red on blue97% 29 / 308.0$0.13161.0 s7.0 mm
Blue cube in the box, cluttered table97% 29 / 308.2$0.13663.7 s24.1 mm
Stack blue on red, cluttered table83% 25 / 308.0$0.13059.9 s17.8 mm

Averages per trial. Cost is computed from token counts at list price. With the scripted reference planner in place of Claude, the same five Franka tasks solve 250 of 250 trials (50 seeds each), which isolates grounding, control and execution from planning.

All of it is open

Apache-2.0, one repository: the engine you just ran, the Python reference stack and the benchmark harness.

# get the code
git clone https://github.com/jay7828/Dooms-inference
cd Dooms-inference

# build the browser engine
npm install && npm run build

# or run the Python stack, no AWS needed
uv venv .venv --python 3.11
uv pip install --python .venv/bin/python -e ".[dev]"
.venv/bin/python scripts/run_task.py \
    --task put_bottle_in_box --seed 0 --llm scripted

Other things we built