A phone scan becomes a scene you can push around. One 26-second iPhone video of a table, four ways to get its 3D geometry, and the pipeline we kept: 6.4 minutes from capture to a MuJoCo scene for the hand demo.
Same 32 frames, same object models after this step. Each scene is dropped into the simulator and left to settle. The tan table is the same size in every video. Videos 1–3 used the first, automatic object masks, which cut the spoon into a handle and a head; video 4 is the final pipeline.
Clean, upright shapes. A video alone cannot tell how big the table is.
Merging all depth frames into one volume wears thin objects away. The mug and jar come out misshapen and tip over.
Right size, but the low-resolution depth glues the spoon to the plate and finds placemats as objects.
VGGT-Omega's shapes at the scale of the phone's camera path. No LiDAR needed. Shown as the final pipeline builds it: objects found by Claude + SAM 3, each resized to fit its masks.

Methods 1–4 all used the first object finder: SAM 2 proposes masks with no text, and a mask is kept if the depth says something stands on the table. It breaks in a different way with each depth source. Replacing it with Claude's object names + SAM 3 fixed the spoon, the placemats and the count in one step.
Each tile tints one thing it kept. Placemats and chairs pass the test because 256 × 192 LiDAR is noisy at edges. Plate and spoon are one object.
No placemats, but the spoon is cut into a handle and a head. That is the odd spoon in video 1.
Claude names what is on the table; SAM 3 masks exactly those names in every frame. Four objects, each whole.
Method 4 for geometry, then three fixes that mattered more than the depth source: object names from Claude, masks from SAM 3, and a size fit to the masks.


Rows: photo, AnySplat seen from the phone's camera, LiDAR depth, AnySplat depth. Streaky renders, and it cannot take the phone's cameras as input.
Shape error against LiDAR after removing a common 4 % scale offset. Cameras help DA3, but VGGT-Omega without cameras is already more accurate. DA3 Large, 16 frames, one scene.

# Record with Stray Scanner (iPhone or iPad), copy the capture folder over, then: python sm120.py fast_scene.py NAME CAPTURE_DIR # options --objects claude # default: Claude names the objects, SAM 3 masks them --objects auto # no names: SAM 2 proposals filtered by depth (splits thin objects, keeps placemats) --prompts "plate,mug,toy duck*2" # name the objects yourself instead of asking Claude --set-down # put every object flat on the table --no-export # stop before the MuJoCo scene # the scene lands in ~/recon_scenes/NAME; in the hand demo: uv run python scripts/live.py --world mujoco --scene NAME
| Step | Script | Time |
|---|---|---|
| Frames and phone cameras | phone_capture.py | 11 s |
| Geometry at phone scale | run_video.py (VGGT-Omega) | 8 s |
| Object names | caption_objects.py (Claude) | 6–16 s |
| Masks | masks_sam3.py | 15 s |
| Object meshes | run_fast.py, run_stage2.py (SAM 3D) | 151 s |
| Texture and size | bake_texture.py, fit_silhouette.py | 81 s |
| MuJoCo scene, real table texture | export_mujoco.py, surface_texture.py | 91 s |
| Splats | scene_splat.py | 6 s |
Code: experiments repo, projects/scene-reconstruction/2026-10-15_tabletop-recon, branch won/phone-depth. Needs one 32 GB GPU. Mass and friction of the objects are guesses.