Skip to content

Entity Options

Entity options describe one thing in the scene: a mesh or URDF/MJCF asset (EntityOptions, RobotOptions), a primitive shape, a terrain, a bank of per-env variants (GroupedEntityOptions) or a multi-entity rig (CompositeEntityOptions). SceneOptions holds them as named children; each name becomes the key of env.entities. The entities guide explains pose frames, DOF fields and contact parameters; the scenes guide covers scenes and terrain.

from eden.options.entities import BoxOptions, SceneOptions

scene_options = SceneOptions(box=BoxOptions(size=(0.1, 0.1, 0.1), default_root_pos=(0.0, 0.0, 0.6)))

Quaternion fields (default_root_quat, ...) are wxyz.

Scene

SceneOptions

SceneOptions(**data)

Bases: DynamicConfigurableOptions

Scene options for Eden, specifying the entities to construct the scene.

PARAMETER DESCRIPTION
attachments_dict

A dictionary of entity_name -> (attach_to_entity_name, attach_to_link_name), optionally with a mounting offset: entity_name -> (attach_to_entity_name, attach_to_link_name, attach_offset, attach_quat). e.g., {"gripper": ("arm", "attachment")} or {"gripper": ("arm", "attachment", (0.0, 0.0, 0.1), (1.0, 0.0, 0.0, 0.0))}. Without an offset, the attached entity's default_root_pos / default_root_quat act as the mounting transform relative to the parent link. The optional attach_offset (xyz) and attach_quat (wxyz) override it (see RigidEntity.attach_to).

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

attachments_dict class-attribute instance-attribute

attachments_dict: dict[str, AttachmentSpec] = {}

Methods:

named_entities

named_entities() -> dict[str, BaseEntityOptions]

Every entity the scene will build, keyed by final entity name (composites expanded).

Source code in eden/options/entities.py
def named_entities(self) -> dict[str, BaseEntityOptions]:
    """Every entity the scene will build, keyed by final entity name (composites expanded)."""
    out: dict[str, BaseEntityOptions] = {}
    for key, entity in (self.__pydantic_extra__ or {}).items():
        if key.startswith("_option_"):
            continue
        if isinstance(entity, CompositeEntityOptions):
            out.update(entity.entity_options())
        elif isinstance(entity, BaseEntityOptions):
            out[key] = entity
    return out

remove_entity

remove_entity(name: str) -> None

Remove the entity placed under scene key name, together with its own attachment.

The supported way for a task variant to drop an entity (see eden/tasks/robosuite/variants.py::drop_object). Only an entity added by name (an extra) is removable; one declared as a field of a SceneOptions subclass (DroidSceneOptions.robot) is part of that scene class. An attachments_dict entry that welds the removed entity onto a parent goes with it. An entity that other entities are welded onto cannot be removed — remove the children first. Nothing else that names the entity is touched — manager terms, cameras, sensors — so update those too, otherwise they fail to resolve the entity at build time.

PARAMETER DESCRIPTION
name

Scene key of the entity. A composite is removed whole, under its placement key; one of its bodies cannot be removed on its own.

TYPE: str

RAISES DESCRIPTION
RuntimeError

If the scene options are locked (checked before anything else).

KeyError

If the scene has no entity name (the message lists the removable entities), or name cannot be removed: a declared field, or a body of a composite (the message says which).

ValueError

If another entity is attached to the one being removed.

Source code in eden/options/entities.py
def remove_entity(self, name: str) -> None:
    """Remove the entity placed under scene key ``name``, together with its own attachment.

    The supported way for a task variant to drop an entity (see
    ``eden/tasks/robosuite/variants.py::drop_object``). Only an entity added by
    name (an extra) is removable; one declared as a field of a ``SceneOptions`` subclass
    (``DroidSceneOptions.robot``) is part of that scene class. An ``attachments_dict`` entry
    that welds the removed entity onto a parent goes with it. An entity that *other* entities
    are welded onto cannot be removed — remove the children first. Nothing else that names
    the entity is touched — manager terms, cameras, sensors — so update those too, otherwise
    they fail to resolve the entity at build time.

    Parameters
    ----------
    name : str
        Scene key of the entity. A composite is removed whole, under its placement key; one of
        its bodies cannot be removed on its own.

    Raises
    ------
    RuntimeError
        If the scene options are locked (checked before anything else).
    KeyError
        If the scene has no entity ``name`` (the message lists the removable entities), or
        ``name`` cannot be removed: a declared field, or a body of a composite (the message
        says which).
    ValueError
        If another entity is attached to the one being removed.
    """
    try:
        entity = self._removable_child(name, noun="entity")
    except KeyError as err:
        # The generic "not found" would be wrong for an entity that exists but is not an extra.
        reason = self._unremovable_entity_reason(name)
        if reason is None:
            raise
        raise KeyError(reason) from err
    # A composite produces several scene entities (arm + gripper); all of them go with it.
    removed_names = set(entity.entity_names) if isinstance(entity, CompositeEntityOptions) else {name}
    dependents = sorted(
        child
        for child, spec in self.attachments_dict.items()
        if spec[0] in removed_names and child not in removed_names
    )
    if dependents:
        raise ValueError(
            f"Cannot remove entity '{name}': {dependents} are attached to it via attachments_dict. "
            f"Remove those entities first."
        )

    self._remove_named_child(name, noun="entity")
    # Rebuilt, not edited in place: a shallow model_copy() shares the dict with its source scene,
    # which would silently lose its own welds.
    self.attachments_dict = {
        child: spec for child, spec in self.attachments_dict.items() if child not in removed_names
    }

Base and asset entities

BaseEntityOptions

BaseEntityOptions(**data)

Bases: ConfigurableOptions

Shared options for entities.

PARAMETER DESCRIPTION
default_root_pos

Default root position.

TYPE: array - like[float, float, float]

default_root_quat

Default root orientation as quaternion in (w, x, y, z).

TYPE: array - like[float, float, float, float]

is_fixed_base

Whether the entity base is fixed.

TYPE: bool

is_articulated

Whether the entity has articulation.

TYPE: bool

is_actuated

Whether the entity is actuated.

TYPE: bool

material

Material used for the entity.

TYPE: MaterialLike | None

surface

Surface appearance used for the entity. Prefer an Eden :class:SurfaceOptions (e.g. PlasticSurfaceOptions(color=(1.0, 0.0, 0.0))) in configs constructed before gs.init(); a raw gs.surfaces.* instance is also accepted.

TYPE: SurfaceOptions | Surface | None

color

Convenience shortcut to color the entity. When set (and surface is not), a plastic surface with this color (RGB or RGBA) is created at build time.

TYPE: array - like[float] | None

visualize_contact

Whether to visualize contacts involving this entity.

TYPE: bool

vis_mode

Visualization mode for the entity.

TYPE: VisMode

visualization

Whether to visualize the entity.

TYPE: bool

collision

Whether this entity participates in collision checking.

TYPE: bool

contype

32-bit collision-filter bitmask. Two geoms can collide only if the contype of one and the conaffinity of the other share a set bit. Defaults to 0xFFFF.

TYPE: int

conaffinity

32-bit collision-filter bitmask. See contype. Defaults to 0xFFFF.

TYPE: int

collision_link_patterns

Regex/glob patterns matched against link names. When set, only geoms on matching links keep collision; geoms on all other links are disabled (contype = conaffinity = 0). Use to restrict an entity's collisions to specific parts — e.g. a parallel-jaw gripper's fingertip pads ([".*pad"]) so objects are grasped at the pads instead of wedging against the inner linkage. Applied before the scene is built (Genesis bakes the collision-pair list at build time). None keeps the morph's default per-geom collision.

TYPE: list of str

collision_friction

Friction coefficient applied to the geoms kept by collision_link_patterns (e.g. high pad friction for stable grasps).

TYPE: float

batch_fixed_verts

Whether fixed-geometry vertices are batched for per-env transforms.

TYPE: bool

is_support_enabled

Whether support-point computation is enabled.

TYPE: bool

support_sample_method

The method to sample the support points. Defaults to "uniform".

TYPE: Literal['uniform', 'grid']

support_minimum_clearance

The minimum clearance to be considered for support points. Defaults to 0.05.

TYPE: float

support_shrink

The shrink factor to be applied to the support points. Defaults to 0.1.

TYPE: float

support_num_sample_points

The number of support points to sample per square meter of polygon. Defaults to 300.

TYPE: int

support_grid_size

The size of the grid to sample the support points when support_sample_method is "grid". Defaults to 0.01.

TYPE: float

support_links_name

Exact link names (URDF link names / MJCF body names) whose geometry should be considered when extracting support surfaces. Empty (default) means all links contribute. Use this on multi-link assets (e.g. the Riverway franka station) to restrict placement targets to a specific surface like ["station_table_top"] so events don't spawn objects onto auxiliary cart / gantry tops.

TYPE: list[str]

dofs_name

Controllable DOF names.

TYPE: list[str]

dofs_spec

Class-level default actuator specification map for DOFs.

TYPE: ClassVar[dict[str, type[ActuatorSpecOptions]]]

default_dofs_pos

Default DOF positions.

TYPE: dict[str, float]

default_dofs_vel

Default DOF velocities.

TYPE: dict[str, float]

default_dofs_kp

Default DOF position gains.

TYPE: dict[str, float]

default_dofs_kd

Default DOF velocity gains.

TYPE: dict[str, float]

default_dofs_stiffness

Default DOF stiffness values.

TYPE: dict[str, float]

default_dofs_damping

Default DOF damping values.

TYPE: dict[str, float]

default_dofs_armature

Default DOF armature values.

TYPE: dict[str, float]

default_dofs_frictionloss

Default DOF dry-friction (stiction) torques. Values below the drive torque leave actuation unaffected while absorbing sub-threshold oscillation (contact chatter).

TYPE: dict[str, float]

default_dofs_spring_ref

Re-anchor a DOF's passive spring (default_dofs_stiffness / the file's joint stiffness) at this reference position instead of the initial qpos. Genesis ignores MJCF springref and anchors joint springs at qpos0, which silently drops any preload (e.g. the Robotiq 2F85's spring links). Implemented at build by moving the spring to a position servo: sim stiffness is zeroed and the DOF gets kp = stiffness with the reference as its (persistent) position target — do not also drive these DOFs from an action term.

TYPE: dict[str, float]

default_dofs_pos_limits

Hard DOF position limits.

TYPE: dict[str, array - like[float, float]]

soft_dofs_pos_limits

Soft DOF position limits.

TYPE: dict[str, array - like[float, float]]

default_dofs_force_limits

Default DOF force limits.

TYPE: dict[str, float]

default_equalities_sol_params

Constraint solver parameters (timeconst, dampratio, dmin, dmax, width, mid, power) applied to all of the entity's equality constraints (loop closures, joint couplings) at build. Note genesis clamps timeconst to 2*substep_dt, so a stiff value needs a matching sim_dt/sim_substeps.

TYPE: SolParamsType | None

default_geoms_sol_params

Constraint solver parameters for the collision geoms of links matching each key (exact name, glob, or regex — same semantics as collision_link_patterns). Note genesis mixes a contact pair's parameters as the mean of its two geoms' values (MuJoCo geom priority is not honored), so the partner geom should be stiffened too for the pair to reach the requested stiffness.

TYPE: dict[str, SolParamsType]

default_geoms_friction

Friction for the collision geoms of links matching each key (same pattern semantics as default_geoms_sol_params), applied at build — e.g. a dexterous hand's fingertips ({".*_DP": 1.5}) while the whole hand keeps colliding. Unlike sol params the partner geom needs no matching value, since genesis combines a pair's friction as max(a, b). Prefer this over collision_friction, which only covers the geoms kept by collision_link_patterns and disables collision elsewhere.

TYPE: dict[str, float]

default_geoms_friction_torsional

Torsional friction (spin resistance about the contact normal, in meters) for the collision geoms of links matching each key — same pattern and max(a, b) pair semantics as default_geoms_friction. Use it when only part of an entity needs the strength the material-wide RigidMaterialOptions.friction_torsional would apply everywhere, e.g. a dexterous hand whose fingertips resist an object twisting in the grasp more than its palm does. Written after the material coefficient, so it wins on the geoms it matches. Requires EnvOptions.enable_torsional_friction.

TYPE: dict[str, float]

default_geoms_friction_rolling

Rolling friction (resistance about the two contact tangent axes, in meters) for the collision geoms of links matching each key. Same semantics as default_geoms_friction_torsional, but requires EnvOptions.enable_rolling_friction and costs two extra constraint axes per contact instead of one.

TYPE: dict[str, float]

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

material class-attribute instance-attribute

material: MaterialLike | None = None

surface class-attribute instance-attribute

surface: SurfaceLike | None = None

color class-attribute instance-attribute

color: FArrayType | None = None

visualize_contact class-attribute instance-attribute

visualize_contact: bool = False

vis_mode class-attribute instance-attribute

vis_mode: VisMode = 'visual'

metadata class-attribute

metadata: MetadataOptions | None = None

visualization class-attribute instance-attribute

visualization: bool = True

collision class-attribute instance-attribute

collision: bool = True

contype class-attribute instance-attribute

contype: int = 65535

conaffinity class-attribute instance-attribute

conaffinity: int = 65535
collision_link_patterns: list[str] | None = None

collision_friction class-attribute instance-attribute

collision_friction: float | None = None

batch_fixed_verts class-attribute instance-attribute

batch_fixed_verts: bool = False

is_support_enabled class-attribute instance-attribute

is_support_enabled: bool = False

support_sample_method class-attribute instance-attribute

support_sample_method: Literal['uniform', 'grid'] = 'uniform'

support_minimum_clearance class-attribute instance-attribute

support_minimum_clearance: float = 0.05

support_shrink class-attribute instance-attribute

support_shrink: float = 0.1

support_num_sample_points class-attribute instance-attribute

support_num_sample_points: int = 300

support_grid_size class-attribute instance-attribute

support_grid_size: float = 0.01
support_links_name: list[str] = []

default_root_pos class-attribute instance-attribute

default_root_pos: Vec3FType = (0.0, 0.0, 0.0)

default_root_quat class-attribute instance-attribute

default_root_quat: UnitVec4FType = (1.0, 0.0, 0.0, 0.0)

is_fixed_base class-attribute instance-attribute

is_fixed_base: bool = False

is_articulated class-attribute instance-attribute

is_articulated: bool = False

is_actuated class-attribute instance-attribute

is_actuated: bool = False

dofs_name class-attribute instance-attribute

dofs_name: list[str] = []

dofs_spec class-attribute

dofs_spec: dict[str, type[ActuatorSpecOptions]] = {}

default_dofs_pos class-attribute instance-attribute

default_dofs_pos: dict[str, float] = {}

default_dofs_vel class-attribute instance-attribute

default_dofs_vel: dict[str, float] = {}

default_dofs_kp class-attribute instance-attribute

default_dofs_kp: dict[str, float] = {}

default_dofs_kd class-attribute instance-attribute

default_dofs_kd: dict[str, float] = {}

default_dofs_stiffness class-attribute instance-attribute

default_dofs_stiffness: dict[str, float] = {}

default_dofs_damping class-attribute instance-attribute

default_dofs_damping: dict[str, float] = {}

default_dofs_armature class-attribute instance-attribute

default_dofs_armature: dict[str, float] = {}

default_dofs_frictionloss class-attribute instance-attribute

default_dofs_frictionloss: dict[str, float] = {}

default_dofs_spring_ref class-attribute instance-attribute

default_dofs_spring_ref: dict[str, float] = {}

default_dofs_pos_limits class-attribute instance-attribute

default_dofs_pos_limits: dict[str, Vec2FType] = {}

soft_dofs_pos_limits class-attribute instance-attribute

soft_dofs_pos_limits: dict[str, Vec2FType] = {}

default_dofs_force_limits class-attribute instance-attribute

default_dofs_force_limits: dict[str, float] = {}

default_equalities_sol_params class-attribute instance-attribute

default_equalities_sol_params: SolParamsType | None = None

default_geoms_sol_params class-attribute instance-attribute

default_geoms_sol_params: dict[str, SolParamsType] = {}

default_geoms_friction class-attribute instance-attribute

default_geoms_friction: dict[str, float] = {}

default_geoms_friction_torsional class-attribute instance-attribute

default_geoms_friction_torsional: dict[str, float] = {}

default_geoms_friction_rolling class-attribute instance-attribute

default_geoms_friction_rolling: dict[str, float] = {}

EntityOptions

EntityOptions(**data)

Bases: BaseEntityOptions

Entity options for Eden, wrapping Genesis' Entity related options.

PARAMETER DESCRIPTION
up

The object's up direction in its own coordinate system (use gs view to visualize that coordinate system). On loading, the object is rotated so this axis becomes world +z.

front

The object's front direction in its own coordinate system (use gs view to visualize that coordinate system). On loading, the object is rotated so this axis becomes world +x.

local_dir

Where the asset is cached. Unset, it is the family's assets_subdir under the asset root, resolved at load time by :meth:resolve_local_dir; :meth:fetch_asset downloads into it.

file

Path to the entity file.

scale

Scale of the entity: uniform, or along each axis of the asset's frame (a scanned mesh measured to a real object's size, say). Unequal axes need a mesh file (:data:MESH_FILE_SUFFIXES); URDF, MJCF and USD assets scale uniformly.

collision

Whether the entity needs to be considered for collision checking. Defaults to True.

decimate

Whether to decimate (simplify) the mesh. Defaults to True. This is only used for RigidEntity.

TYPE: bool

decimate_face_num

The number of faces to decimate to. Defaults to 1000. This is only used for RigidEntity.

TYPE: int

decimate_aggressiveness

How hard the decimation process will try to match the target number of faces, as an integer ranging from 0 to 8. 0 is lossless. 2 preserves all features of the original geometry. 5 may significantly alter the original geometry if necessary. 8 does what needs to be done at all costs. Defaults to 3. This is only used for RigidEntity.

TYPE: int

convexify

Whether to convexify the entity. When convexify is True, all the meshes in the entity will each be converted to a set of convex hulls. The mesh will be decomposed into multiple convex components if the convex hull is not sufficient to meet the desired accuracy (see 'decompose_(robot|object)_error_threshold' documentation). The module 'coacd' is used for this decomposition process. If not given, it defaults to True for RigidEntity and False for other deformable entities.

TYPE: bool

decompose_object_error_threshold

For basic rigid objects (mug, table...), skip convex decomposition if the relative difference between the volume of original mesh and its convex hull is lower than this threshold. 0.0 to enforce decomposition, float("inf") to disable it completely. Defaults to 0.15 (15%).

TYPE: float

decompose_robot_error_threshold

For poly-articulated robots, skip convex decomposition if the relative difference between the volume of original mesh and its convex hull is lower than this threshold. 0.0 to enforce decomposition, float("inf") to disable it completely. Defaults to float("inf").

TYPE: float

coacd_threshold

The threshold for the CoACD algorithm. Defaults to 0.05.

TYPE: float

coacd_preprocess_resolution

The resolution for the CoACD algorithm. Defaults to 100.

TYPE: int

links_to_keep

A list of link names that should not be skipped during link merging. Defaults to [].

TYPE: list of str

align

Whether Genesis re-frames a floating root link onto its centre of mass and principal axes. None (default) lets Genesis decide: on for a basic rigid object (one free root body, nothing articulated under it), off otherwise. An aligned link's centre of mass and inertia belong to the solver and cannot be written after build, so set False on an object whose inertial properties a task randomizes per env (a COM offset, a per-env inertia); its free joint then sits at the authored body frame, as in MuJoCo, so for a single-body free object get_pos() equals get_pos(relative=True) (and likewise get_quat). The cost: the unaligned free body loses its diagonal mass block (linear and angular motion couple through the COM offset), the numerical-stability benefit alignment exists for.

TYPE: bool | None

default_armature

Rotor inertia Genesis fills in at scene.build() for every DOF of a body moved by a single hinge or slide joint whose armature the asset leaves at zero: every URDF joint (URDF has no armature element) and any MJCF joint that omits armature or authors it as 0. Ball, free and multi-joint bodies are skipped, and a nonzero authored value is kept. 0.0 disables the fill. Defaults to 0.1, usually far too high for low-stiffness joints, so set default_dofs_armature from the source asset instead of inheriting it.

TYPE: float

is_fixed_base

Whether the entity is fixed in the environment. A URDF, USD or mesh asset is built to match. An MJCF is not — Genesis has no fixed switch for it — so declare what the file says: False when its base body carries a <freejoint/>, True when it has no joint or any other joint of its own (hinge, slide or ball). A mismatch raises at build.

is_articulated

Whether the entity is articulated.

is_actuated

Whether the entity is actuated.

default_root_pos

The default position of the loaded entity's root link. Will not take effect if the entity is attached to another entity.

default_root_quat

The default orientation of the loaded entity's root link (w, x, y, z). Will not take effect if the entity is attached to another entity.

dofs_name

The names of the DOFs to be treated as controllable DOFs.

dofs_spec

Class-level default actuator specification map for entity DOFs.

TYPE: ClassVar[dict[str, type[ActuatorSpecOptions]]]

default_dofs_pos

The default positions of the DOFs of the entity.

default_dofs_vel

The default velocities of the DOFs of the entity.

default_dofs_kp

The default control position gains of the DOFs of the entity.

default_dofs_kd

The default control velocity gains of the DOFs of the entity.

default_dofs_stiffness

The default stiffnesses of the DOFs of the entity. If provided, the value will be used over the stiffness in dofs_spec.

default_dofs_damping

The default dampings of the DOFs of the entity. If provided, the value will be used over the damping in dofs_spec.

default_dofs_armature

The default armatures of the DOFs of the entity. If provided, the value will be used over the armature in dofs_spec.

default_dofs_pos_limits

The position limits of the DOFs of the entity.

soft_dofs_pos_limits

The position limits of the DOFs of the entity that are treated as soft DOFs.

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

up class-attribute instance-attribute

up: tuple[int, int, int] = (0, 0, 1)

front class-attribute instance-attribute

front: tuple[int, int, int] = (1, 0, 0)

file class-attribute instance-attribute

file: str = ''

registry class-attribute instance-attribute

registry: str = DEFAULT_ASSET_REGISTRY

dataset class-attribute instance-attribute

dataset: str = DEFAULT_ASSET_DATASET

local_dir class-attribute instance-attribute

local_dir: str | None = None

scale class-attribute instance-attribute

scale: float | tuple[float, float, float] = 1.0

decimate class-attribute instance-attribute

decimate: bool = True

decimate_face_num class-attribute instance-attribute

decimate_face_num: int = 1000

decimate_aggressiveness class-attribute instance-attribute

decimate_aggressiveness: int = 3

convexify class-attribute instance-attribute

convexify: bool = True

recompute_inertia class-attribute instance-attribute

recompute_inertia: bool = False

decompose_object_error_threshold class-attribute instance-attribute

decompose_object_error_threshold: float = 0.15

decompose_robot_error_threshold class-attribute instance-attribute

decompose_robot_error_threshold: float = float('inf')

coacd_threshold class-attribute instance-attribute

coacd_threshold: float = 0.05

coacd_preprocess_resolution class-attribute instance-attribute

coacd_preprocess_resolution: int = 100
links_to_keep: list[str] = []

align class-attribute instance-attribute

align: bool | None = None

default_armature class-attribute instance-attribute

default_armature: float = 0.1

mjcf_follows_is_fixed_base class-attribute

mjcf_follows_is_fixed_base: bool = False

assets_subdir class-attribute

assets_subdir: str = ''

Methods:

resolve_local_dir

resolve_local_dir() -> str

Where this entity's asset is cached: local_dir, else assets_subdir under the asset root.

Resolved on each call, never stored: EDEN_ASSETS_DIR then moves every default, and a saved config's local_dir stays unset. To fetch a file, call :meth:fetch_asset.

Source code in eden/options/entities.py
def resolve_local_dir(self) -> str:
    """Where this entity's asset is cached: ``local_dir``, else ``assets_subdir`` under the asset root.

    Resolved on each call, never stored: ``EDEN_ASSETS_DIR`` then moves every default, and a saved
    config's ``local_dir`` stays unset. To fetch a file, call :meth:`fetch_asset`.
    """
    return resolve_local_dir(self.local_dir, self.assets_subdir)

fetch_asset

fetch_asset(file: str | None = None) -> str

The local path of file (default: self.file) from this entity's Hub dataset, downloaded if missing.

Fetches with this entity's registry, dataset and :meth:resolve_local_dir. Call this rather than get_asset_path(..., local_dir=options.local_dir): an unset local_dir passed on raw would fetch into the asset root instead of the family's assets_subdir, and nothing would fail.

Source code in eden/options/entities.py
def fetch_asset(self, file: str | None = None) -> str:
    """The local path of ``file`` (default: ``self.file``) from this entity's Hub dataset, downloaded if missing.

    Fetches with this entity's ``registry``, ``dataset`` and :meth:`resolve_local_dir`. Call this rather
    than ``get_asset_path(..., local_dir=options.local_dir)``: an unset ``local_dir`` passed on raw would
    fetch into the asset root instead of the family's ``assets_subdir``, and nothing would fail.
    """
    return get_asset_path(
        self.file if file is None else file,
        registry=self.registry,
        dataset=self.dataset,
        local_dir=self.resolve_local_dir(),
    )

fetch_family_asset classmethod

fetch_family_asset(file: str) -> str

The local path of file from this family's default Hub dataset, downloaded if missing.

For a file the family's dataset ships that no entity is built from (a task catalogue's BDDL file, a background image), so there is no options instance to call :meth:fetch_asset on: fetches with the class's default registry/dataset/local_dir, the last resolved like :meth:resolve_local_dir. Nothing is validated as an entity, so the file may be of any type.

RAISES DESCRIPTION
ValueError

When the family declares no Hub registry/dataset default, so there is no dataset to fetch from.

Source code in eden/options/entities.py
@classmethod
def fetch_family_asset(cls, file: str) -> str:
    """The local path of ``file`` from this family's default Hub dataset, downloaded if missing.

    For a file the family's dataset ships that no entity is built from (a task catalogue's BDDL file, a
    background image), so there is no options instance to call :meth:`fetch_asset` on: fetches with the
    class's default ``registry``/``dataset``/``local_dir``, the last resolved like :meth:`resolve_local_dir`.
    Nothing is validated as an entity, so the file may be of any type.

    Raises
    ------
    ValueError
        When the family declares no Hub ``registry``/``dataset`` default, so there is no dataset to fetch from.
    """
    fields = cls.model_fields
    registry, dataset = fields["registry"].default, fields["dataset"].default
    if registry is None or dataset is None:
        raise ValueError(
            f"{cls.__name__}.fetch_family_asset({file!r}): the family has no Hub dataset to fetch from "
            f"(registry={registry!r}, dataset={dataset!r}). Give {cls.__name__} registry and dataset defaults, "
            f"or open a local file directly instead of fetching it."
        )
    return get_asset_path(
        file,
        registry=registry,
        dataset=dataset,
        local_dir=resolve_local_dir(fields["local_dir"].default, cls.assets_subdir),
    )

resolve_runtime_file

resolve_runtime_file() -> str

Return the asset descriptor consumed while building the runtime entity.

Subclasses may derive a loadable descriptor from the serialized source asset. The returned path is runtime state and must not be written back to file.

Source code in eden/options/entities.py
def resolve_runtime_file(self) -> str:
    """Return the asset descriptor consumed while building the runtime entity.

    Subclasses may derive a loadable descriptor from the serialized source asset.
    The returned path is runtime state and must not be written back to ``file``.
    """
    return self.file

RobotOptions

RobotOptions(**data)

Bases: EntityOptions

Robot entity options for Eden.

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

is_actuated class-attribute instance-attribute

is_actuated: bool = True

is_articulated class-attribute instance-attribute

is_articulated: bool = True

actuated_dofs_name class-attribute

actuated_dofs_name: list[str] = []
ee_links_name: list[str] = []
feet_links_name: tuple[str, ...] = ()
gantry_links_name: tuple[str, ...] = ()

tcp_offset class-attribute

tcp_offset: tuple[float, float, float] | None = None

stroke class-attribute

stroke: float | None = None

max_substep_dt class-attribute

max_substep_dt: float | None = None

MetadataOptions

MetadataOptions(**data)

Bases: DynamicConfigurableOptions

Metadata options for Entity, used to store additional metadata about the entity.

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Primitives

PrimitiveOptions

PrimitiveOptions(**data)

Bases: BaseEntityOptions

Base options for primitive shapes.

PARAMETER DESCRIPTION
default_root_pos

Default root position.

TYPE: array - like[float, float, float]

default_root_quat

Default root orientation as quaternion in (w, x, y, z).

TYPE: array - like[float, float, float, float]

fixed

Whether the entity is fixed.

is_articulated

Whether the entity has articulation.

TYPE: bool

is_actuated

Whether the entity is actuated.

TYPE: bool

material

Material used for the entity.

TYPE: MaterialLike | None

surface

Surface appearance used for the entity. Prefer an Eden :class:SurfaceOptions in configs constructed before gs.init().

TYPE: SurfaceOptions | Surface | None

color

Convenience shortcut to color the entity (RGB or RGBA) without a full surface.

TYPE: array - like[float] | None

visualize_contact

Whether to visualize contacts involving this entity.

TYPE: bool

vis_mode

Visualization mode for the entity.

TYPE: VisMode

collision

Whether this entity participates in collision checking.

TYPE: bool

batch_fixed_verts

Whether fixed-geometry vertices are batched for per-env transforms.

TYPE: bool

is_support_enabled

Whether support-point computation is enabled.

TYPE: bool

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

fixed class-attribute instance-attribute

fixed: bool = False

morph class-attribute instance-attribute

morph: Morph | dict | None = None

PlaneOptions

PlaneOptions(**data)

Bases: PrimitiveOptions

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

fixed class-attribute instance-attribute

fixed: bool = True

normal class-attribute instance-attribute

normal: UnitVec3FType = (0.0, 0.0, 1.0)

plane_size class-attribute instance-attribute

plane_size: PositiveVec2FType = (1000.0, 1000.0)

tile_size class-attribute instance-attribute

tile_size: PositiveVec2FType = (1.0, 1.0)

Methods:

get_morph

get_morph() -> Primitive
Source code in eden/options/entities.py
def get_morph(self) -> gs.morphs.Primitive:
    return gs.morphs.Plane(
        **self._collect_morph_kwargs(
            normal=self.normal,
            plane_size=self.plane_size,
            tile_size=self.tile_size,
        ),
    )

BoxOptions

BoxOptions(**data)

Bases: PrimitiveOptions

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

size class-attribute instance-attribute

size: Vec3FType = (0.1, 0.1, 0.1)

Methods:

get_morph

get_morph() -> Primitive
Source code in eden/options/entities.py
def get_morph(self) -> gs.morphs.Primitive:
    return gs.morphs.Box(
        **self._collect_morph_kwargs(
            size=self.size,
        ),
    )

SphereOptions

SphereOptions(**data)

Bases: PrimitiveOptions

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

radius class-attribute instance-attribute

radius: float = 0.1

Methods:

get_morph

get_morph() -> Primitive
Source code in eden/options/entities.py
def get_morph(self) -> gs.morphs.Primitive:
    return gs.morphs.Sphere(
        **self._collect_morph_kwargs(
            radius=self.radius,
        ),
    )

CylinderOptions

CylinderOptions(**data)

Bases: PrimitiveOptions

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

radius class-attribute instance-attribute

radius: float = 0.1

height class-attribute instance-attribute

height: float = 0.1

Methods:

get_morph

get_morph() -> Primitive
Source code in eden/options/entities.py
def get_morph(self) -> gs.morphs.Primitive:
    return gs.morphs.Cylinder(
        **self._collect_morph_kwargs(
            radius=self.radius,
            height=self.height,
        ),
    )

RodOptions

RodOptions(**data)

Bases: PrimitiveOptions

A discrete elastic rod on a polyline (eden.engine.solvers.mochi.morphs.Rod), for the Mochi solver only.

The morph is the centerline; the material must be a :class:~eden.options.materials.MochiRodMaterialOptions, which derives the rod's stiffness from radius unless given explicitly. Clamp a rod after build by fixing its first two nodes (env.entities[name].set_vertices_fixed([0, 1])). default_root_pos / default_root_quat place the whole polyline; is_fixed_base has no meaning for a rod and is rejected.

PARAMETER DESCRIPTION
points

Centerline nodes (at least two, consecutive nodes distinct), in the rod's own frame.

TYPE: array - like[n_nodes, 3]

radius

Circular cross-section radius (m). Default is 0.01.

TYPE: float

n_cross_section_segments

Tube tessellation used for rendering only. Default is 12.

TYPE: int

is_closed_loop

Connect the last node back to the first. Default is False.

TYPE: bool

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

points instance-attribute

points: list[tuple[float, float, float]]

radius class-attribute instance-attribute

radius: float = 0.01

n_cross_section_segments class-attribute instance-attribute

n_cross_section_segments: int = 12

is_closed_loop class-attribute instance-attribute

is_closed_loop: bool = False

Methods:

get_morph

get_morph() -> Rod
Source code in eden/options/entities.py
def get_morph(self) -> Rod:
    # ``eden.engine.solvers.mochi.morphs.Rod`` inherits only ``Morph`` (no ``fixed`` / ``contype`` /
    # ``conaffinity`` / ``batch_fixed_verts``), and genesis options forbid extras, so the generic
    # ``_collect_morph_kwargs`` would be rejected — assemble the accepted subset by hand.
    kwargs: dict[str, object] = {
        "points": np.asarray(self.points, dtype=float),
        "radius": self.radius,
        "n_cross_section_segments": self.n_cross_section_segments,
        "is_closed_loop": self.is_closed_loop,
        "pos": self.default_root_pos,
        "quat": self.default_root_quat,
        "collision": self.collision,
        "visualization": self.visualization,
    }
    if isinstance(self.morph, dict):
        kwargs.update(**self.morph)
    elif isinstance(self.morph, Morph):
        kwargs.update(**self.morph.model_dump())
    return Rod(**kwargs)

Terrain

TerrainOptions

TerrainOptions(**data)

Bases: BaseEntityOptions

Terrain entity options for Eden, wrapping Genesis' Terrain related options.

Note that all dofs/articulation-related fields are set to empty/False and is_fixed_base is always set to True.

PARAMETER DESCRIPTION
horizontal_scale

The size of each cell in the subterrain in meters. Defaults to 0.25.

TYPE: float

vertical_scale

The height of each step in the subterrain in meters. Defaults to 0.005.

TYPE: float

subterrain_size

The size of each subterrain in meters. Defaults to (32.0, 32.0), which holds every built-in parkour course at its shipped defaults (they run out to ~29 m). On a shorter strip the parkour generators pull the final goal back into the walkable area, and raise once the course cannot fit at all (see eden/utils/terrains/parkour_terrains.py); tuned courses fit far shorter lanes — eden/tasks/extreme_parkour runs 16 x 4 m.

TYPE: tuple of float

uv_scale

How many times the surface texture repeats across the whole terrain, as (x, y); a scalar applies to both axes. None (the default) means auto: one repeat per axis for a custom surface, and for use_checker_surface the count that renders 1 m checker squares. Give a tuple when the terrain is not square and the texture must not stretch with it — a single figure spreads one repeat over each axis's full extent, so a 160 x 40 m terrain would render squares 4x wider than they are deep.

TYPE: float or tuple of float or None

randomize

Whether to randomize the subterrains that involve randomness. Defaults to False.

TYPE: bool

terrain_generators

Terrain generator configuration grid.

TYPE: list[list[TerrainTermOptions]]

use_checker_surface

Whether to render checkerboard surface instead of a custom surface.

TYPE: bool

material

Material used for terrain.

TYPE: MaterialLike | None

surface

Surface appearance used for terrain.

TYPE: SurfaceOptions | Surface | None

visualize_contact

Whether to visualize contacts involving terrain.

TYPE: bool

vis_mode

Visualization mode for terrain.

TYPE: VisMode

is_support_enabled

Whether support-point computation is enabled.

TYPE: bool

default_root_pos

Default root position.

TYPE: array - like[float, float, float]

default_root_quat

Default root orientation as quaternion in (w, x, y, z).

TYPE: array - like[float, float, float, float]

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

horizontal_scale class-attribute instance-attribute

horizontal_scale: float = 0.25

vertical_scale class-attribute instance-attribute

vertical_scale: float = 0.005

subterrain_size class-attribute instance-attribute

subterrain_size: Vec2FType = (32.0, 32.0)

uv_scale class-attribute instance-attribute

uv_scale: float | Vec2FType | None = None

randomize class-attribute instance-attribute

randomize: bool = False

terrain_generators class-attribute instance-attribute

terrain_generators: list[list[TerrainTermOptions]] = [[FlatTerrain.configure()]]

use_checker_surface class-attribute instance-attribute

use_checker_surface: bool = False

uv_repeats property

uv_repeats: tuple[float, float] | None

uv_scale as an explicit (x, y) pair, or None when it is left on auto.

The scalar and pair spellings differ only here; everything downstream reads the pair.

TerrainTermOptions

TerrainTermOptions(**data)

Bases: DynamicConfigurableOptions

TerrainGenerator options for Eden, configure by TerrainGenerator.configure().

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

The terrain generators a TerrainOptions composes are on the robotics utilities page.

Per-env variants

GroupedEntityOptions

GroupedEntityOptions(**data)

Bases: BaseEntityOptions

Grouped entity used for heterogeneous batching.

Supports both non-articulated entities (Mesh, Primitive) and articulated entities (URDF) that share the same joint structure (same number of links, joints, and DOFs).

Each variant contributes its morph (file or shape, mesh processing, its own default_root_pos / default_root_quat), and may hold its own value for some of the group's fields. A variant holds a value when it differs from the field's default, whether passed in or its catalog class's default.

  • Per variant (variant_values(), variant_materials): the geom fields (default_geoms_friction*, default_geoms_sol_params), the per-DOF ones (default_dofs_* and soft_dofs_pos_limits) and the material's rho / friction*. Each env takes its variant's own value, else the group's. Variants that differ in a simulated DOF field (gains, stiffness, damping, armature, frictionloss, force limits) need EnvOptions(batch_dofs_info=True). A per-variant rho rescales each env's mass after the build, so it needs a mesh or primitive variant, whose mass Genesis computes from its density.
  • Shared (shared_dof_fields(), shared_dofs_spec): dofs_name and default_dofs_spring_ref, the group's own or, when it sets none, that of the first variant that sets one; a variant's own different value is refused. So is a variant class's dofs_spec that differs from another's.
  • Group only: every other field (surface, color, is_fixed_base, the support and collision mask fields, the other material fields): a variant's own different value is refused.

A variant overrides the group's own value for a per-variant field only with a value other than its class's default: one equal to the class default is read as inherited and refused, as the group's value would silently skip it. The group's value is also refused when every variant overrides it, as it would apply to none of them. check_variants runs these checks; the entity runs it again before the build.

PARAMETER DESCRIPTION
grouped_entities

A list of entity configurations to be grouped.

TYPE: list[EntityOptions | PrimitiveOptions]

is_fixed_base

Whether grouped entities should be treated as fixed base.

TYPE: bool

dofs_name

Controllable DOF names shared by the group.

TYPE: list[str]

dofs_spec

Class-level default actuator specification map for grouped DOFs.

TYPE: ClassVar[dict[str, type[ActuatorSpecOptions]]]

default_dofs_pos

Default grouped DOF positions.

TYPE: dict[str, float]

default_dofs_vel

Default grouped DOF velocities.

TYPE: dict[str, float]

default_dofs_kp

Default grouped DOF position gains.

TYPE: dict[str, float]

default_dofs_kd

Default grouped DOF velocity gains.

TYPE: dict[str, float]

default_dofs_stiffness

Default grouped DOF stiffness values.

TYPE: dict[str, float]

default_dofs_damping

Default grouped DOF damping values.

TYPE: dict[str, float]

default_dofs_armature

Default grouped DOF armature values.

TYPE: dict[str, float]

default_dofs_pos_limits

Hard grouped DOF position limits.

TYPE: dict[str, array - like[float, float]]

soft_dofs_pos_limits

Soft grouped DOF position limits.

TYPE: dict[str, array - like[float, float]]

default_dofs_force_limits

Default grouped DOF force limits.

TYPE: dict[str, float]

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

grouped_entities class-attribute instance-attribute

grouped_entities: list[EntityOptions | PrimitiveOptions] = Field(default_factory=list)

variant_materials property

variant_materials: list[MaterialLike]

Each variant's material: the group's, with the variant's own rho and friction coefficients.

shared_dofs_spec property

shared_dofs_spec: dict[str, type[ActuatorSpecOptions]]

The actuator specs every variant shares: a variant's own dofs_spec, else the group's.

Methods:

check_variants

check_variants() -> None

Refuse what the variants hold that the entity cannot apply as configured (raises ValueError).

Run at construction, and again by the entity before the scene is built: a TaskMod or any other code that assigns a field of the group or of a variant after construction never re-runs model_post_init, so its edit would otherwise go unchecked.

Source code in eden/options/entities.py
def check_variants(self) -> None:
    """Refuse what the variants hold that the entity cannot apply as configured (raises ``ValueError``).

    Run at construction, and again by the entity before the scene is built: a TaskMod or any other code
    that assigns a field of the group or of a variant after construction never re-runs
    ``model_post_init``, so its edit would otherwise go unchecked.
    """
    self._refuse_variant_group_only_values()
    self._refuse_variant_shared_dof_values()
    for i, variant in enumerate(self.grouped_entities):
        if variant.material is not None:
            self._refuse_variant_material(i, variant.material)
    self._refuse_implicit_variant_overrides()
    self._refuse_unused_group_values()

variant_values

variant_values() -> dict[str, list]

Each variant's value for every per-variant field: its own, else the group's.

Source code in eden/options/entities.py
def variant_values(self) -> dict[str, list]:
    """Each variant's value for every per-variant field: its own, else the group's."""
    return {
        name: [getattr(v if _has_own_value(v, name) else self, name) for v in self.grouped_entities]
        for name in _PER_VARIANT_FIELD_NAMES
    }

shared_dof_fields

shared_dof_fields() -> dict[str, object]

The DOF fields every variant shares (dofs_name, default_dofs_spring_ref).

Each is the group's own value, else that of the first variant that sets one. Resolved on read rather than copied onto the group: once a config is dumped a copy cannot be told from a value the group set, so an override that swaps the bank would keep the old one's.

Source code in eden/options/entities.py
def shared_dof_fields(self) -> dict[str, object]:
    """The DOF fields every variant shares (``dofs_name``, ``default_dofs_spring_ref``).

    Each is the group's own value, else that of the first variant that sets one. Resolved on read rather
    than copied onto the group: once a config is dumped a copy cannot be told from a value the group set, so
    an override that swaps the bank would keep the old one's.
    """
    return {name: getattr(self._shared_dof_source(name), name) for name in _SHARED_DOF_FIELD_NAMES}

Composite rigs

The base of the composite robot presets (an arm plus a hand, a humanoid plus two hands); see robot presets.

CompositeEntityOptions

CompositeEntityOptions(**data)

Bases: ConfigurableOptions

A composite of several entities added to a scene as a single unit.

A composite is a real, validated Options (it round-trips through the config system and declares its own fields). It stays in :class:SceneOptions as-is — a task adds it by name like any other entity, SceneOptions(robot=Droid(...)) — and the env build loop expands it into ordinary entities + weld wiring (see RLEnvBase scene construction). A composite adds no runtime behaviour of its own beyond "these named entities + these welds", which env.entities + attach_to already provide, so there is deliberately no composite runtime entity.

Subclasses describe the rig by implementing :meth:entity_parts (the ordered (name, sub-entity Options) pairs) and, when parts are welded, :meth:attachments; :meth:entity_options keys those parts by name, refusing a collision that would otherwise cost the rig a body silently. The scene placement key must equal :attr:primary_name (the root body), so the key is meaningful (not silently discarded) and downstream terms can reference the sub-entities by the composite's own names. Concrete composites — an arm + gripper (a manipulator), a humanoid + hands — live in eden/options/robots/composite.

Source code in eden/options/options.py
def __init__(self, **data):
    # Seed type metadata as construction data so BaseModel validates it into
    # __pydantic_extra__ (no-op for extra="forbid" classes, which use
    # the serialization envelope instead).
    data.update(option_metadata(self))
    # NOTE: all of the option modifications/validations should be done in the __init__ method
    try:
        BaseModel.__init__(self, **data)
    except ValidationError as exc:
        # A misspelled field on an extra="forbid" class should teach the field set, not just
        # name the typo. Only rewritten when every error is extra_forbidden.
        enriched = _enrich_extra_forbidden(type(self), exc)
        if enriched is None:
            raise
        raise enriched from None

Attributes

entity_names property

entity_names: list[str]

Scene entity names this composite produces.

primary_name property

primary_name: str

The root body's name — the scene placement key must equal this.

Methods:

entity_parts

entity_parts() -> list[tuple[str, 'BaseEntityOptions']]

The named sub-entities this composite is built from, in declaration order (uncopied).

A list, not a dict, because this is the only place two bodies sharing a name are still visible — :meth:entity_options collapses them. Implement this rather than :meth:entity_options so the duplicate check there covers every composite shape.

Source code in eden/options/entities.py
def entity_parts(self) -> list[tuple[str, "BaseEntityOptions"]]:
    """The named sub-entities this composite is built from, in declaration order (uncopied).

    A *list*, not a dict, because this is the only place two bodies sharing a name are still
    visible — :meth:`entity_options` collapses them. Implement this rather than
    :meth:`entity_options` so the duplicate check there covers every composite shape.
    """
    raise NotImplementedError(f"{type(self).__name__} must implement entity_parts().")

entity_options

entity_options() -> dict[str, 'BaseEntityOptions']

The named sub-entities keyed by name (uncopied), and where a name collision is caught.

Framework-owned: subclasses implement :meth:entity_parts instead, so this check cannot be bypassed by method dispatch.

Two bodies under one name collapse to a single entry, leaving the composite one body short with nothing downstream noticing: :attr:entity_names, :meth:expand and the cross-composite check in :meth:SceneOptions.model_post_init all read this dict, so none of them can see what has already been overwritten. Checked here, on every call, not only at construction (:meth:model_post_init calls this) — these Options do not validate_assignment, so a *_name reassigned after construction would slip past a construction-time-only guard.

Source code in eden/options/entities.py
def entity_options(self) -> dict[str, "BaseEntityOptions"]:
    """The named sub-entities keyed by name (uncopied), and where a name collision is caught.

    Framework-owned: subclasses implement :meth:`entity_parts` instead, so this check cannot
    be bypassed by method dispatch.

    Two bodies under one name collapse to a single entry, leaving the composite one body
    short with nothing downstream noticing: :attr:`entity_names`, :meth:`expand` and the
    cross-composite check in :meth:`SceneOptions.model_post_init` all read *this* dict, so
    none of them can see what has already been overwritten. Checked here, on every call, not
    only at construction (:meth:`model_post_init` calls this) — these Options do not
    ``validate_assignment``, so a ``*_name`` reassigned after construction would slip past a
    construction-time-only guard.
    """
    parts = self.entity_parts()
    names = [name for name, _ in parts]
    collisions = sorted({name for name in names if names.count(name) > 1})
    if collisions:
        raise ValueError(
            f"{type(self).__name__} gives two bodies the same name {collisions}, but a "
            f"composite's entity names ARE the scene's entity names, so each body needs its "
            f"own; got {names}. Set the colliding '*_name' field(s) to something distinct."
        )
    return dict(parts)

attachments

attachments() -> dict[str, AttachmentSpec]

Weld wiring: child entity -> (parent entity, parent link[, mount pos, mount quat]).

Default: none. See :attr:SceneOptions.attachments_dict for the optional offset form.

Source code in eden/options/entities.py
def attachments(self) -> dict[str, AttachmentSpec]:
    """Weld wiring: child entity -> (parent entity, parent link[, mount pos, mount quat]).

    Default: none. See :attr:`SceneOptions.attachments_dict` for the optional offset form.
    """
    return {}

expand

expand() -> tuple[dict[str, 'BaseEntityOptions'], dict[str, tuple[str, str]]]

Return (named_entities, attachments) for the scene build loop.

The sub-entity Options are deep-copied so one composite instance can be placed in several scenes (or reused from the registry) without the scenes aliasing — and mutating — the same Options. (copy.deepcopy — not pydantic model_copy — because genesis' Options define __deepcopy__(self, memo).)

Source code in eden/options/entities.py
def expand(self) -> tuple[dict[str, "BaseEntityOptions"], dict[str, tuple[str, str]]]:
    """Return ``(named_entities, attachments)`` for the scene build loop.

    The sub-entity Options are deep-copied so one composite instance can be placed in
    several scenes (or reused from the registry) without the scenes aliasing — and
    mutating — the same Options. (``copy.deepcopy`` — not pydantic ``model_copy`` —
    because genesis' Options define ``__deepcopy__(self, memo)``.)
    """
    entities = {name: copy.deepcopy(opts) for name, opts in self.entity_options().items()}
    return entities, dict(self.attachments())

See also