Skip to content

dh.object

Extension: .dh-obj
Type ID: dh.object

An object is a reusable building block: an accessory, outfit, prop, or any composable piece. Objects define what they are through a list of patches, ordered operations that import models, assign materials, set transforms, and more.

dh.avatar extends this type.

PropertyTypeRequiredDescription
$type"dh.object"noType identifier
namestringnoDisplay name
descriptionstringnoDescription
inheritsstringnoBarcode of the object to inherit from
patchesarraynoOrdered list of patches to apply

The type is inferred from the file extension, so $type is not needed in source files. The compiler adds it automatically during builds.

ears.dh-obj
{
"name": "Cat Ears",
"patches": [
{
"$type": "dh.import-model",
"path": "models/ears.glb"
},
{
"$type": "dh.set-material",
"target": "Ears",
"slot": 0,
"path": "materials/fur.dh-mat"
}
]
}

Many patches use a target property to reference objects in the hierarchy. These are hierarchical paths using the object names from imported models:

  • "Body": a root-level object named Body
  • "Armature": a root-level armature
  • "Armature/Hips/Spine": nested path through the hierarchy

Target paths are resolved after all imports, so you can reference objects from any previously-imported model.


Patches are applied in order. Each patch has a $type that identifies what it does.

Import a 3D model file into the hierarchy.

PropertyTypeRequiredDescription
$type"dh.import-model"yes
pathstringyesModel file path (.glb or .fbx, relative to pallet root)
asstringnoRename the import root object
{
"$type": "dh.import-model",
"path": "models/body.glb",
"as": "MainBody"
}

FBX files are automatically converted to GLB via Blender during compilation.


Import another dh.object definition, bringing in all of its patches.

PropertyTypeRequiredDescription
$type"dh.import-object"yes
pathstringyesObject definition path (relative or barcode)
asstringnoRename the import root
parentstringnoParent object path to attach under
{
"$type": "dh.import-object",
"path": "accessories/glasses/glasses.dh-obj",
"parent": "Head"
}

Cross-pallet import:

{
"$type": "dh.import-object",
"path": "io.mltn.accessories:glasses/glasses.dh-obj"
}

Remove an object from the hierarchy. If the target doesn’t exist, a warning is logged but no error is raised.

PropertyTypeRequiredDescription
$type"dh.remove-object"yes
targetstringyesHierarchical path of the object to remove
{
"$type": "dh.remove-object",
"target": "Armature/Hips/TailBone"
}

Assign a dh.material to a specific material slot on a mesh.

PropertyTypeRequiredDescription
$type"dh.set-material"yes
targetstringyesTarget mesh path
slotintyesMaterial slot index (0-based)
pathstringyesMaterial definition path (relative or barcode)
{
"$type": "dh.set-material",
"target": "Body",
"slot": 0,
"path": "materials/skin.dh-mat"
}

Set the value of a blendshape (morph target) on a mesh.

PropertyTypeRequiredDescription
$type"dh.set-blendshape"yes
targetstringyesTarget mesh path
blendshapestringyesBlendshape name
valuefloatyesValue (typically 0.0 – 1.0)
{
"$type": "dh.set-blendshape",
"target": "Body",
"blendshape": "smile",
"value": 0.75
}

Set position, rotation, and/or scale on an object. Only the properties you specify are changed.

PropertyTypeRequiredDescription
$type"dh.set-transform"yes
targetstringyesTarget object path
position[x, y, z]noPosition in local space
rotation[x, y, z]noRotation in degrees (Euler)
scalenumber or [x, y, z]noScale (single number = uniform)
{
"$type": "dh.set-transform",
"target": "Glasses",
"position": [0, 0.1, 0.05],
"scale": [1.1, 1.1, 1.1]
}

A single number for scale is treated as uniform scale on all axes. "scale": 1.1 is equivalent to "scale": [1.1, 1.1, 1.1].

{
"$type": "dh.set-transform",
"target": "Glasses",
"scale": 1.1
}

Move an object under a new parent in the hierarchy.

PropertyTypeRequiredDescription
$type"dh.set-parent"yes
targetstringyesObject to reparent
parentstringyesNew parent object path
firstboolnoIf true, makes it the first child (default: false)
{
"$type": "dh.set-parent",
"target": "HairAccessory",
"parent": "Head",
"first": true
}

Apply a dh.rig definition to an armature, mapping standard bone names to model-specific bone names.

PropertyTypeRequiredDescription
$type"dh.set-rig"yes
targetstringyesArmature/skeleton root path
pathstringyesRig definition path (relative or barcode)
meshstringnoHierarchy path to the target SkinnedMeshRenderer for visemes/eyelids
{
"$type": "dh.set-rig",
"target": "Armature",
"path": "rigs/humanoid.dh-rig",
"mesh": "Body"
}

Link a source armature or object to a target armature. Two modes depending on whether the source has a rig:

Bone-to-bone matching: when the source has a DigitalHeavenRig, bones are matched by standard name. Use this to merge clothing armatures with body armatures.

Single-bone attachment: when the source has no rig, it attaches to a specific bone on the target. Requires the bone property.

PropertyTypeRequiredDescription
$type"dh.armature-link"yes
targetstringyesTarget armature path (must have a rig applied via dh.set-rig)
sourcestringyesSource object or armature path
bonestringnoTarget bone name (required for rig-less sources)
alignboolnoAlign source transform with target bone (default: true)

Bone-to-bone example:

{
"$type": "dh.armature-link",
"target": "Armature",
"source": "OutfitArmature"
}

Single-bone attachment:

{
"$type": "dh.armature-link",
"target": "Armature",
"source": "Backpack",
"bone": "Chest",
"align": false
}

When align is true (default), the source’s local transform is reset to match the target bone. Set it to false to preserve the source’s original transform.


Add spring bone physics to a bone chain for secondary motion (hair, tails, ears, skirts, etc.). Automatically discovers all child bones from the target root and simulates them using Verlet integration.

PropertyTypeRequiredDefaultDescription
$type"dh.set-spring-bones"yes
targetstringyesPath to the root bone of the chain
ignorestring[]noChild transform names to exclude (along with their descendants)
stiffnessfloatno0.3Pull toward animated pose (0 = floppy, 1 = locked)
dampingfloatno0.7Oscillation decay (0 = bouncy, 1 = no motion)
gravityfloatno0.0Downward pull strength in world space
{
"$type": "dh.set-spring-bones",
"target": "Body/Armature/Tail1",
"stiffness": 0.2,
"gravity": 0.3
}

Multiple chains on the same avatar:

// In the patches array:
{ "$type": "dh.set-spring-bones", "target": "Body/Armature/Tail1", "stiffness": 0.2, "gravity": 0.3 },
{ "$type": "dh.set-spring-bones", "target": "Body/Armature/EarL1" },
{ "$type": "dh.set-spring-bones", "target": "Body/Armature/EarR1" }

Excluding specific children:

{
"$type": "dh.set-spring-bones",
"target": "Body/Armature/Tail1",
"ignore": ["Tail_IK_Target", "Tail_Collider"]
}

Game mods for platforms with native bone physics (DynamicBone, VRCPhysBone, etc.) can read the spring bone data and translate it to native components, disabling the built-in solver.