Schema Fragments#
Isaac Lab authors physics properties onto USD prims through schema fragments: small
configuration classes that each mirror exactly one USD applied schema and write into a
single attribute namespace. Because fragments compose in lists, one asset configuration
can carry OpenUSD physics (physics:*), PhysX (physx*:*), and Newton
(newton:* / mjc:*) attributes side by side and run on any backend.
This page explains the fragment model, the prim-path expressions that target fragments at prims, and the spawner-level configuration surface. For the solver-common vs. backend-specific class tiers, see Schema Configuration Classes. For the full class and function reference, see isaaclab.sim.schemas.
The fragment model#
Every fragment subclasses SchemaFragment and declares
which USD namespace its fields write to and which applied schema, if any, it owns. A
fragment’s func names the callable that
applies it to a prim; the default applier
(apply_namespaced()) writes each non-None field as
<namespace>:<camelCase(field)> and leaves None fields untouched (partial
update). Irregular APIs override func — for example
UsdPhysicsDriveCfg dispatches through
apply_drive() to handle the multi-instance
UsdPhysics.DriveAPI.
Fragments are grouped into families, one per spawner slot. Each family has a writer
that resolves target prims from an expression and dispatches every fragment via its
func. Backend fragments carry backend-specific appliers, so the core package never
imports a backend:
Spawner field |
Family writer |
Valid targets |
|---|---|---|
|
prims with |
|
|
prims with |
|
|
prims with |
|
|
prims with |
|
|
revolute / prismatic joint prims |
|
|
tendon-bearing prims (existing tendon instances) |
|
|
tendon attachment root / leaf prims |
The tendon families are tune-not-apply: the tendon topology is authored in the source asset, so their writers only tune existing instances and never create them.
Targeting expressions#
Target prims are resolved with find_matching_prims().
The expression is a plain Python regular expression matched against the whole prim
path. Standard regex semantics apply: . matches any character including /, so
/World/Robot/.* selects every descendant at any depth, while [^/]+ confines a
wildcard to a single path segment and /World/Robot(/.*)? selects the prim together
with its descendants. The traversal includes inactive and undefined prims as well as
instance proxies.
The matched set is then filtered to valid family targets (see the table above): API carriers for the rigid-body, collision, mass, and articulation families; revolute and prismatic joint prims for the joint-drive family; tendon-bearing prims for the tendon families. Non-joint matches of a joint-drive expression are ignored silently, since a subtree expression legitimately sweeps whole subtrees.
Edge cases behave as follows:
Instanced matches cannot be authored on (prototypes are read-only) and are skipped with a warning.
Zero targets emit a warning and the writer returns
Falsewithout authoring anything.An empty fragment list is an authoring no-op and returns
True.
Configuring fragments on spawners#
Spawner configurations (UsdFileCfg,
CuboidCfg, …) expose one field per family.
Each field accepts either a mapping from target pattern to a list of fragments, a bare
fragment or list of fragments (see the shorthand below), a
single legacy dataclass cfg (e.g.
RigidBodyBaseCfg or a backend *PropertiesCfg, routed
to the legacy writers), or None.
Mapping keys are regular-expression suffixes appended to the prim the spawner authors
that family on: the spawn prim for USD, URDF, and MJCF assets; for shape and mesh
spawners, the geometry prim for the collision family and the container prim for the
rigid-body and mass families. A key therefore carries its own leading / when it
targets descendants: "" selects the anchor prim itself, "/[^/]+" its direct
children, and "/.*" everything beneath it. Prefer "/.*" for a whole-subtree
rule: the anchor is usually a plain Xform that carries no family API, so including
it changes nothing — except under create_if_missing, where "(/.*)?" would also
apply the API to the anchor itself. Reach for "(/.*)?" only when the anchor is
genuinely a target too. Entries apply in insertion order, so when two patterns match the
same prim, fragments from later entries override attributes authored by earlier ones.
The bare fragment (or list of fragments) shorthand skips the mapping when a rule needs no targeting of its own. On the shape and mesh spawners it targets the anchor prim, the only prim those spawners author. On the file spawners it targets the spawn prim together with its descendants, so it reaches the schema carriers wherever the asset puts them; and when the subtree carries no prim with the family’s defining API at all — the usual shape of an art asset shipped without physics schemas — the file spawners apply that API to the spawn prim and author there, turning the asset into a single body.
A robot spawned from USD, with a broad rule and a narrowing override:
import isaaclab.sim as sim_utils
from isaaclab.sim.schemas import UsdPhysicsDriveCfg, UsdPhysicsRigidBodyCfg
from isaaclab_newton.sim.schemas import MujocoRigidBodyCfg
from isaaclab_physx.sim.schemas import PhysxRigidBodyCfg
from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR
spawn = sim_utils.UsdFileCfg(
usd_path=f"{ISAAC_NUCLEUS_DIR}/Robots/Franka/franka_instanceable.usd",
rigid_props={
# every rigid body: universal + PhysX + MuJoCo attributes side by side
"/.*": [
UsdPhysicsRigidBodyCfg(rigid_body_enabled=True),
PhysxRigidBodyCfg(max_depenetration_velocity=5.0),
MujocoRigidBodyCfg(gravcomp=1.0),
],
# hand links (and their subtrees) get a tighter depenetration limit
"/.*_hand/.*": [PhysxRigidBodyCfg(max_depenetration_velocity=1.0)],
},
joint_drive_props={
"/.*": [UsdPhysicsDriveCfg(drive_type="force", stiffness=40.0, damping=4.0)],
},
)
A primitive shape, where every family targets the anchor prim, so the mapping can be dropped entirely:
import isaaclab.sim as sim_utils
from isaaclab.sim.schemas import MassCfg, UsdPhysicsCollisionCfg, UsdPhysicsRigidBodyCfg
from isaaclab_newton.sim.schemas import NewtonCollisionCfg
cuboid = sim_utils.CuboidCfg(
size=(0.1, 0.1, 0.1),
rigid_props=UsdPhysicsRigidBodyCfg(),
mass_props=MassCfg(mass=0.5),
collision_props=[UsdPhysicsCollisionCfg(collision_enabled=True), NewtonCollisionCfg(contact_margin=0.001)],
)
Reach for the mapping when a rule must target something other than the anchor prim — the usual situation for assets spawned from USD, URDF, or MJCF files, where the spawn prim is a container and the schema carriers sit beneath it.
Creating missing APIs#
By default, the family writers only modify prims that already carry the family’s
defining USD API. Three per-family spawner flags — mass_props_create_if_missing,
articulation_props_create_if_missing, and joint_drive_props_create_if_missing —
additionally apply the defining API to matched prims that lack it before the fragments
are authored (for the joint-drive family, the axis-appropriate UsdPhysics.DriveAPI
instance). Shape and mesh spawners always create the APIs on the bare prims they
author, since freshly created geometry carries no physics APIs yet.
The writers trust the expression as written: with creation enabled, every matched prim receives the API, so a too-broad pattern can, for example, give every mesh in a subtree its own mass. Which bodies participate in an articulation is still decided by the asset’s joints, not by the expression. Scope creation patterns deliberately.
See also#
Schema Configuration Classes — solver-common vs. backend-specific configuration tiers
isaaclab.sim.schemas — fragment base classes and family writers
isaaclab_physx.sim.schemas — PhysX fragments
isaaclab_newton.sim.schemas — Newton / MuJoCo fragments