House of cards (mujoco.org)
Many contacts
A four-storey house of 26 thin playing cards stands on friction alone.
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 mjorg_house_of_cards# change solver settings liveuv run shelf tune mjorg_house_of_cardsSource: examples/shelf/02_many_contacts/mjorg_house_of_cards/ · ported from google-deepmind/mujoco model/cards/house_of_cards.xml (MuJoCo 4.0 tour on mujoco.org)
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
############################################################################ Example mujoco.org house of cards## A four-storey house of 26 playing cards, 0.7 mm thick, standing on friction alone.## Replicates the "House of Cards" scene of the MuJoCo 4.0 tour on mujoco.org from its# MJCF (scene.xml, flattened from google-deepmind/mujoco model/cards/house_of_cards.xml).# See README.md for the gaps.## Command: python -m shelf run mjorg_house_of_cards############################################################################
from pathlib import Path
import numpy as np
import newtonimport newton.examplesfrom common.steel_scenes import SceneExample
# How far a card may move before the house counts as failing [m].CARD_SHIFT_MAX = 0.005
class Example(SceneExample): file = __file__ # MuJoCo's free camera for the scene: azimuth 150, elevation -15 around the statistic centre camera = {"eye": (0.44, -0.25, 0.24), "target": (0.0, 0.0, 0.1)}
def build(self): builder = newton.ModelBuilder() self.preset.apply_model(builder) builder.add_mjcf(str(Path(__file__).with_name("scene.xml"))) self.start = np.array([list(builder.body_q[b])[:3] for b in range(builder.body_count)]) return builder, {}
def check(self): """Every card stays where it was built.""" self.solver.check_constraint_capacity() # dropped contact rows invalidate the run q = self.state_0.body_q.numpy() shift = np.linalg.norm(q[:, :3] - self.start, axis=1) assert shift.max() < CARD_SHIFT_MAX, ( f"{int((shift >= CARD_SHIFT_MAX).sum())} cards moved, up to {shift.max():.4f} m" )
if __name__ == "__main__": parser = Example.create_parser() viewer, args = newton.examples.init(parser) newton.examples.run(Example(viewer, args), args)example = "mjorg_house_of_cards"source = "google-deepmind/mujoco model/cards/house_of_cards.xml (MuJoCo 4.0 tour on mujoco.org)"license = "Apache-2.0"default = "steel"
[check]# Arguments `python -m shelf check` passes in test mode.args = ["--num-frames", "1200"]
[gallery]short = "A four-storey house of 26 thin playing cards stands on friction alone."title = "House of cards (mujoco.org)"frame = 60
[xpbd]status = "untested"
[vbd]status = "untested"
[mujoco]status = "untested"
[featherstone]status = "untested"
[semi_implicit]status = "untested"
[feather_pgs]status = "untested"
[steel]status = "works"# Nesterov momentum with warm start keeps the apex pair standing; every colored propagation setting tried# (4-32 substeps, 16-64 iterations) loses it within 2 s.sim = { fps = 60, substeps = 8 }model = { rigid_gap = 0.002 }solver = { solve_mode = "serial", iterations = 32, articulated_contact_response = "immediate", nesterov_momentum = true, contact_warmstart = true, free_body_constraint_max = 4096 }checked = "2026-11-10, newton f6fc82a8b, NVIDIA RTX PRO 6000 Blackwell Server Edition"
[kamino]status = "untested"
[implicit_mpm]status = "untested"
[style3d]status = "untested"README
Steel replica of “House of Cards” from the MuJoCo 4.0 tour on mujoco.org. 26 playing cards, 0.7 mm thick, make a four-storey house that stands on friction alone.
- Source:
google-deepmind/mujocomodel/cards/house_of_cards.xmland itsassets/, Apache-2.0 (text inLICENSE).scene.xmlis that file compiled with MuJoCo 3.17 and re-emitted flat; the card textures are downscaled to 256 x 256. - Check: after 20 s no card has moved more than 5 mm, and no contact rows were dropped.
Known gaps:
- Steel needs Nesterov momentum with contact warm start (serial solve, immediate response) at 2 ms steps. With the colored solve and propagation response the apex pair slides apart within 2 s at every setting tried.
- MuJoCo’s contacts are soft and over-damped (
solref0.005 3), with an elliptic cone,impratio10 and two noslip iterations; Steel’s contacts are hard. Air density and viscosity are not modelled. - The tour lets the user drag a card; the shelf scene runs untouched.
- Rendering uses the shelf viewer, not MuJoCo’s Filament renderer.
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.