Tutorials
One short script per Steel feature. Each replay is a recording of that exact script on a GPU, played back in 3D. Where a tutorial compares settings, the variants run side by side with one option changed. The scripts are intutorials/; run one withcd tutorials && python 01_hello_steel.py.
Getting started
Contact and friction
- 03Patch friction vs point frictionfriction_anchor_beta
- 04Friction combine modesfriction_combine
- 05Global friction scalecontact_friction_scale
- 06Spin and rolling frictionsteel:condim
- 07Torsional friction on articulated bodiessteel:min_torsional_patch_radius
- 08Friction update modesfriction_mode
- 09Shape typesadd_shape_*
- 10Kinematic bodies and per-body gravityis_kinematic / disable_gravity
- 11Conveyor beltsMesh(enable_surface_velocity=True)
- 12Fewer friction rowscontact_friction_position_iterations / contact_friction_gap_max
- 13Shared contact anchorscontact_friction_shared_anchor / contact_shared_anchor
- 14Free-body angular friction defaultsfree_rigid_torsional_friction / free_rigid_rolling_friction
Impacts and penetration
Compliance and adhesion
Convergence
Joints and drives
- 29Joint typesadd_joint_revolute / _prismatic / _ball / _d6 / _fixed / _free
- 30PD drivestarget_ke / target_kd
- 31Drive saturationdrive_mode
- 32Joint limitsenable_joint_limits
- 33Joint velocity limitsenable_joint_velocity_limits
- 34Dry joint frictionenable_joint_friction
- 35Load-dependent joint frictionsteel:joint_friction_load_coefficient
- 36Joint springs and dampingstiffness / rest_q / damping
- 37Armaturearmature
- 38Joint limit activation gapjoint_limit_activation_gap
- 39Drive rows in velocity iterationsvelocity_drive_mode / fuse_joint_velocity_limits
- 40Tethers and distance jointsadd_joint_ball + add_joint_prismatic(limit_lower=-L, limit_upper=0)
Mimic joints and loop closures
Bodies
Solver and runtime
- 50Sleeping islandsenable_sleeping
- 51Run-to-run determinismdeterministic
- 52Heterogeneous worldsbegin_world / end_world
- 53Per-world resetsolver.reset(state, world_mask)
- 54Solve modessolve_mode / articulated_contact_response
- 55CUDA graph capturewp.ScopedCapture / wp.capture_launch
- 56Row capacity and overflowrow_watermark / check_constraint_capacity()
- 57Joint reaction forcessolver.observables({"body_parent_f"})
- 58Changing the model at runtimesolver.notify_model_changed(flags)
- 59Mass-matrix update intervalupdate_mass_matrix_interval
- 60Performance optionsparallel_tree / use_parallel_streams / double_buffer / reuse_kinematics
- 61Propagation optionspropagation_same_articulation_rows / propagation_cached_response / propagation_color_order
- 62Large-scale RL setupsolver.reset(state, world_mask) + eval_fk(mask=...)
- 63Contact sensorsSensorContact(model, sensing_bodies=..., counterpart_shapes=...)
Coupling
Domain randomization
- 65Randomizing masssolver.notify_model_changed(ModelFlags.BODY_INERTIAL_PROPERTIES)
- 66Randomizing the center of massmodel.body_com
- 67Randomizing inertiaupdate_mass_matrix_interval
- 68Randomizing frictionmodel.shape_material_mu
- 69Randomizing restitutionmodel.shape_material_restitution
- 70Randomizing joint dampingmodel.joint_damping
- 71Randomizing joint frictionSolverSteel(model, enable_joint_friction=True)
- 72Randomizing armaturemodel.joint_armature
- 73Randomizing drive gainsmodel.joint_target_ke / joint_target_kd
- 74Randomizing effort limitsmodel.joint_effort_limit
- 75Randomizing joint velocity limitsSolverSteel(model, enable_joint_velocity_limits=True)
- 76Randomizing gravitymodel.set_gravity(g, world=w)
- 77Random pushesstate.joint_qd / state.body_f
- 78Randomizing terrain frictionSolverSteel(model, friction_combine=...)
- 79Several randomizations at oncenotify_model_changed(flags, world_mask=mask)
Planned tutorials
Steel supports these features, and tutorials for them are still to be written or recorded.
- USD import of Steel attributesReading physxRigidBody:* and newton:steel:* attributes from USD works through add_usd; the recording environment has no USD runtime, so this tutorial is still to be recorded.
- MuJoCo equality constraintsEnabled MJCF equality constraints that the importer converts to loop joints or mimic rows.
- State edits with carried kinematicsnotify_state_changed after writing joint_q, joint_qd or body_q outside step when reuse_kinematics is on.
- CPU deviceThe world-serial portable kernels, and which features stay CUDA only.
Domain randomization: not covered yet
Needs a new solver (rebuild instead of notify)
- Turning a solver feature on or off. Options such as
enable_joint_friction,enable_joint_velocity_limits,enable_joint_limits,friction_combine,restitution_combine,drive_modeand the row capacities are fixed whenSolverSteelis constructed. Randomize the values those features read, not whether the features exist. - Restitution with sparse mass factors. A solver that uses sparse mass factors raises
ValueErrorwhen a shape notification gives a shape positive restitution. Construct the solver with the restitution you will need. - Making a kinematic body dynamic. A kinematic free body that was removed from the dynamics at construction cannot become dynamic again.
Not shown or not yet validated
- Collision geometry and offsets. Shape scale, transforms, contact margin and gap are covered by
SHAPE_PROPERTIES, but randomizing them changes contact generation and is not demonstrated here. - Swapping shapes between variants (
Model.select_body_variants,SHAPE_TYPE_AND_SOURCE) is experimental and is meant for resets, not every step. - Per-world friction on a shared ground plane. A ground plane added to the global world is one shape with one coefficient. Give each world its own floor shape instead (see the terrain friction tutorial).
- Contact stiffness and damping (
shape_material_ke,shape_material_kd): Steel's default rigid-contact rows are constraints and do not read these arrays, so randomizing them has no effect there. The experimental opt-incontact_complianceroute for hydroelastic contacts has its own stiffness and damping inputs and is not covered here. - CUDA graph capture of every notification. Joint, joint DOF, body inertial and shape notifications can be captured. Body (kinematic flag) notifications, sleeping, and shape notifications on a solver with sparse mass factors and restitution enabled read data on the host and must run outside capture. A captured notification also skips the eager validation of joint friction and rolling or torsional friction coefficients; notify eagerly to get those checks.
Outside the solver
- Actuator latency and delays, observation noise and action noise belong in the environment or actuator model that feeds
Control, not in the physics solver. - Explicit (framework-side) actuator models keep their own gains; randomize those in the actuator model, because the simulator's drive gains are usually zero in that setup.
Not supported by Steel yet: tendons through native routes, ROD joints, particles and soft bodies (Steel simulates rigid bodies and articulations; couple it with another solver for those), gradients, mimic joints across articulations, and loop closures between two dynamic articulations, and limits on a root DISTANCE joint (Steel simulates it as a free joint and ignores its minimum and maximum distance; use a ball joint and a limited prismatic joint, as in the tether tutorial).
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.