Toaster
Articulations
Insert a slice of bread and press the toaster lever.
steel preset (the default), recordedon an NVIDIA RTX PRO 6000 Blackwell, sped up 2× (the readout shows sim time).Run it
cd examples# the default preset (steel), then the othersuv run shelf play toaster# change solver settings liveuv run shelf tune toasterSource: examples/shelf/07_articulations/toaster/ · ported from steel-webgpu assets/scenes/toaster (hero_montage export) @ ad03e49
Presets
| Preset | Solver | Status | Checked |
|---|---|---|---|
steeldefault | steel | 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 Toaster## The arm turns a bread slice upright, drops it into the second slot and presses the lever; the spring-loaded carriage latches down.## Rebuilt from steel-webgpu's exported scene (assets/scenes/toaster: scene.json# and scene.bin, copied next to this file); see common/exported_scene.py. The# visual meshes draw when a steel-webgpu checkout sits next to the shelf.## scene.json filters the carriage against the bread-guide wires it overlaps at# its upper limit, so the prismatic joint alone governs the lift.## Command: python -m shelf run toaster############################################################################
import numpy as np
import newtonimport newton.examplesfrom common.exported_scene import ExportedSceneExample
CARRIAGE = "procgen/toaster/bread_lift_0"
class Example(ExportedSceneExample): file = __file__
def build(self): builder, twists = super().build() # The bread guides are eight static wire capsules (r = 1 mm) leaning 1.8 degrees, and the carriage's slice # rests are 0.4 mm wider than the gap between them, so they overlap the wires by up to 1.3 mm wherever the # carriage is. The leaning contact normals then wedge the carriage up 4 cm past its upper limit in the first # frame, and the lever press jams it against the narrowing guides instead of latching it down. In a toaster # the carriage passes through the guides; only the bread rides on them, so the carriage ignores the wires. lift = builder.body_label.index(CARRIAGE) wires = [ s for s in range(builder.shape_count) if builder.shape_body[s] == -1 and builder.shape_type[s] == newton.GeoType.CAPSULE ] carriage = [s for s in range(builder.shape_count) if builder.shape_body[s] == lift] for w in wires: for c in carriage: builder.add_shape_collision_filter_pair(w, c) # The toaster's shell and feet are welded to the world and sit 1.7 mm into the table: 32 contact rows every # step (two thirds of the scene's contacts) between bodies that cannot move. Skip them. welded = set() grew = True while grew: grew = False for j, kind in enumerate(builder.joint_type): child, parent = builder.joint_child[j], builder.joint_parent[j] if kind == newton.JointType.FIXED and child not in welded and (parent == -1 or parent in welded): welded.add(child) grew = True static = [s for s in range(builder.shape_count) if builder.shape_body[s] == -1] fixed = [s for s in range(builder.shape_count) if builder.shape_body[s] in welded] for s in static: for w in fixed: builder.add_shape_collision_filter_pair(s, w) return builder, twists
def check(self): """The slice goes into the second slot and the press latches the carriage down: the carriage ends below -0.08 (latched at -0.088) and the inserted slice sits in slot 2 beside the preloaded one, lowered with it.""" q = self.state_0.joint_q.numpy() carriage = float(q[self.model.joint_q_start.numpy()[16]]) # bread_lift_0.q assert carriage < -0.08, f"the carriage is at {carriage:.4f}, not latched down" labels = self.model.body_label inserted = self.state_0.body_q.numpy()[labels.index("toaster/inserted-bread"), :3] preloaded = self.state_0.body_q.numpy()[labels.index("toaster/preloaded-bread"), :3] assert abs(inserted[2] - preloaded[2]) < 0.015, ( f"the inserted slice is at z={inserted[2]:.3f}, the preloaded one at {preloaded[2]:.3f}" ) assert abs(inserted[0] - 0.285) < 0.015 and abs(inserted[1] - 0.12) < 0.02, ( f"the inserted slice ended at {np.round(inserted, 3)}, not in slot 2" )
if __name__ == "__main__": parser = Example.create_parser() viewer, args = newton.examples.init(parser) newton.examples.run(Example(viewer, args), args)example = "toaster"source = "steel-webgpu assets/scenes/toaster (hero_montage export) @ ad03e49"default = "steel"
[check]# Arguments `python -m shelf check` passes in test mode: 1200 frames, the whole 1193-frame task, latched; the example's check() asserts the outcome.args = ["--num-frames", "1200"]
[gallery]short = "Insert a slice of bread and press the toaster lever."title = "Toaster"frame = 420
[xpbd]status = "untested"
[vbd]status = "untested"
[mujoco]status = "untested"
[featherstone]status = "untested"
[semi_implicit]status = "untested"
[feather_pgs]status = "untested"
[steel]status = "works"# 4 substeps x 16 iterations, immediate response: 5.7 ms a frame on an RTX PRO 6000 (the port's colored 4 x 16:# 13.4 ms, 9.6 ms once the welded shell stopped colliding with the table). The slice goes into the second slot, the# press takes the carriage to -0.088 and the latch holds it, as in a 16 x 32 run (slices within 5 mm); penetration# 1.9 mm peak (one frame of the press), 0.12 mm mean. 4 x 8 and 3 substeps keep the task but let the inserted slice# end 4-12 mm off and double the mean penetration. The finger pads' torsion rows (device path) and friction anchors# hold the pinched slice upright; sleeping on (3% faster than off). Joint limits carry the carriage's and the# latch's travel, built within 0.1 of a limit; no joint has a finite velocity limit.sim = { fps = 60, substeps = 4 }solver = { solve_mode = "matrix_free", iterations = 16, articulated_contact_response = "immediate", enable_joint_limits = true, joint_limit_activation_gap = 0.1, enable_joint_velocity_limits = false, contact_torsion_device = true, friction_anchor_beta = 0.2, enable_sleeping = true, free_body_constraint_max = 8192, articulation_constraint_max = 1024 }checked = "2026-11-10, newton f6fc82a8b, NVIDIA RTX PRO 6000 Blackwell Server Edition"
[kamino]status = "untested"
[implicit_mpm]status = "untested"
[style3d]status = "untested"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.