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

rigid_props

apply_rigid_body_properties()

prims with UsdPhysics.RigidBodyAPI

collision_props

apply_collision_properties()

prims with UsdPhysics.CollisionAPI

mass_props

apply_mass_properties()

prims with UsdPhysics.MassAPI

articulation_props

apply_articulation_root_properties()

prims with UsdPhysics.ArticulationRootAPI

joint_drive_props

apply_joint_drive_properties()

revolute / prismatic joint prims

fixed_tendons_props

apply_fixed_tendon_properties()

tendon-bearing prims (existing tendon instances)

spatial_tendons_props

apply_spatial_tendon_properties()

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 False without 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#