Overlapping boxes
Basic contacts
20 boxes start deep inside each other and separate gently.
steel preset (the default), recordedon an NVIDIA RTX PRO 6000 Blackwell.Run it
cd examples# the default preset (steel), then the othersuv run shelf play overlapuv run shelf play overlap --solver steel_off# change solver settings liveuv run shelf tune overlapSource: examples/shelf/01_basic_contacts/overlap/ · ported from steel-webgpu tools/scenes.py overlap() @ ad03e49
Presets
| Preset | Solver | Status | Checked |
|---|---|---|---|
steeldefault | steel | works | 2026-11-10, newton f6fc82a8b, NVIDIA RTX PRO 6000 Blackwell Server Edition |
steel_off | steel variant | works | 2026-11-10, newton f6fc82a8b, NVIDIA RTX PRO 6000 Blackwell Server Edition |
Solvers with no row are untested on this example. The full settings are inpresets.toml.
Code
# SPDX-FileCopyrightText: Copyright (c) 2026 Skild AI and the Steel contributors# SPDX-License-Identifier: Apache-2.0# Direct source: steel-webgpu; see presets.toml and THIRD_PARTY.md.# Modified for Steel Shelf: preset-driven execution and shared runner integration.
############################################################################ Example Overlapping boxes## Velocity pass: boxes spawned 15 mm into each other and the floor.## Ported from steel-webgpu's tools/scenes.py (overlap); the scene builds# as it does there and the shelf's preset drives the solver.## Command: python -m shelf run overlap############################################################################
import math
import numpy as npimport warp as wp
import newtonimport newton.examplesfrom common.steel_scenes import BLUE, GOLD, GREY, RED, TEAL, SceneExample, cfg, tf
class Example(SceneExample): file = __file__ camera = {'eye': (0.5, -1.3, 0.6), 'target': (0.0, 0.0, 0.12)}
def build(self): """Velocity pass: boxes spawned 15 mm into each other and the floor.""" b = newton.ModelBuilder() b.add_ground_plane() for i in range(5): for k in range(4): body = b.add_body(xform=tf(((i - 2) * 0.13, 0.0, 0.035 + 0.055 * k), wp.quat_rpy(0.0, 0.0, 0.3 * k))) b.add_shape_box(body, hx=0.05, hy=0.05, hz=0.035, cfg=cfg(density=400), color=[BLUE, TEAL, GOLD, RED][k]) return b, {}, "Velocity pass: 20 boxes start 15 mm deep in each other; with velocity_iterations the push-out does not launch them."
def check(self): """Every column stands: each box within 2 cm of its column's axis and 5 mm of its stacked height (0.035 + 0.07 k). Not for [steel_off]: without the velocity pass the push-out topples a column, which is what that variant shows.""" if self.preset.name == "steel_off": return q = self.state_0.body_q.numpy()[:, :3].reshape(5, 4, 3) x0 = (np.arange(5) - 2) * 0.13 off = np.hypot(q[..., 0] - x0[:, None], q[..., 1]) assert off.max() < 0.02, f"a box is {1e3 * off.max():.0f} mm off its column" dz = np.abs(q[..., 2] - (0.035 + 0.07 * np.arange(4))) assert dz.max() < 0.005, f"a box sits {1e3 * dz.max():.1f} mm off its stacked height"
if __name__ == "__main__": parser = Example.create_parser() viewer, args = newton.examples.init(parser) newton.examples.run(Example(viewer, args), args)example = "overlap"source = "steel-webgpu tools/scenes.py overlap() @ ad03e49"default = "steel"
[check]# Arguments `python -m shelf check` passes in test mode: 600 frames, 10 s, the columns at rest; the example's check() asserts the outcome.args = ["--num-frames", "600"]
[gallery]short = "20 boxes start deep inside each other and separate gently."title = "Overlapping boxes"frame = 90
[xpbd]status = "untested"
[vbd]status = "untested"
[mujoco]status = "untested"
[featherstone]status = "untested"
[semi_implicit]status = "untested"
[feather_pgs]status = "untested"
[steel]status = "works"# The browser's 4 x 12 overflowed the propagation rows (the 0.1 m contact gap gives the 20 boxes ~1000 rows# against 544) and dropped ~450 rows every step: a column fell over. contact_gap_gate 0.01 keeps only contacts# within 1 cm (~300 rows) and fits.# 3 substeps x 8 iterations: the boxes separate at 0.73 m/s in the first frame and every column stands (drift# 1.4 mm, 5 mm/s jitter at rest). The push-out speed grows with the substep count (16 x 50 throws the boxes,# 1 x 8 is gentler but the columns slide apart after 6 s); 3 x 6 stood here but drifted 27 mm with a 2 cm gate.# No joints: limits off.sim = { fps = 60, substeps = 3 }solver = { solve_mode = "matrix_free", iterations = 8, articulated_contact_response = "propagation_colored", velocity_iterations = 4, contact_gap_gate = 0.01 }checked = "2026-11-10, newton f6fc82a8b, NVIDIA RTX PRO 6000 Blackwell Server Edition"
[kamino]status = "untested"
[implicit_mpm]status = "untested"
[style3d]status = "untested"
[steel_off]kind = "steel"status = "works"# the browser's "Velocity cleanup pass" toggle off: velocity_iterations = 0, the rest as [steel]; the push-out# launches the top boxes (1.7 m/s, 7 cm up) and topples a columnsim = { fps = 60, substeps = 3 }solver = { solve_mode = "matrix_free", iterations = 8, articulated_contact_response = "propagation_colored", velocity_iterations = 0, contact_gap_gate = 0.01 }checked = "2026-11-10, newton f6fc82a8b, NVIDIA RTX PRO 6000 Blackwell Server Edition"Steel docs and tutorials are licensed under Apache-2.0. Third-party notices. "Skild", "Skild AI" and the Skild logo are trademarks of Skild AI and are not licensed under Apache-2.0.