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.
Properties
Section titled “Properties”| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.object" | no | Type identifier |
name | string | no | Display name |
description | string | no | Description |
inherits | string | no | Barcode of the object to inherit from |
patches | array | no | Ordered list of patches to apply |
The type is inferred from the file extension, so
$typeis not needed in source files. The compiler adds it automatically during builds.
Example
Section titled “Example”{ "name": "Cat Ears", "patches": [ { "$type": "dh.importModel", "path": "models/ears.glb" }, { "$type": "dh.setMaterial", "target": "Ears", "slot": 0, "path": "materials/fur.dh-mat" } ]}Target Paths
Section titled “Target Paths”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.
Patch Reference
Section titled “Patch Reference”Patches are applied in order. Each patch has a $type that identifies what it does.
dh.importModel
Section titled “dh.importModel”Import a 3D model file into the hierarchy.
| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.importModel" | yes | |
path | string | yes | Model file path (.glb or .fbx, relative to pallet root) |
as | string | no | Rename the import root object |
{ "$type": "dh.importModel", "path": "models/body.glb", "as": "MainBody"}FBX files are automatically converted to GLB via Blender during compilation.
dh.importObject
Section titled “dh.importObject”Import another dh.object definition, bringing in all of its patches.
| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.importObject" | yes | |
path | string | yes | Object definition path (relative or barcode) |
as | string | no | Rename the import root |
parent | string | no | Parent object path to attach under |
{ "$type": "dh.importObject", "path": "accessories/glasses/glasses.dh-obj", "parent": "Head"}Cross-pallet import:
{ "$type": "dh.importObject", "path": "io.mltn.accessories:glasses/glasses.dh-obj"}dh.removeObject
Section titled “dh.removeObject”Remove an object from the hierarchy. If the target doesn’t exist, a warning is logged but no error is raised.
| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.removeObject" | yes | |
target | string | yes | Hierarchical path of the object to remove |
{ "$type": "dh.removeObject", "target": "Armature/Hips/TailBone"}dh.setMaterial
Section titled “dh.setMaterial”Assign a dh.material to a specific material slot on a mesh.
| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.setMaterial" | yes | |
target | string | yes | Target mesh path |
slot | int | yes | Material slot index (0-based) |
path | string | yes | Material definition path (relative or barcode) |
{ "$type": "dh.setMaterial", "target": "Body", "slot": 0, "path": "materials/skin.dh-mat"}dh.setBlendshape
Section titled “dh.setBlendshape”Set the value of a blendshape (morph target) on a mesh.
| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.setBlendshape" | yes | |
target | string | yes | Target mesh path |
blendshape | string | yes | Blendshape name |
value | float | yes | Value (typically 0.0 – 1.0) |
{ "$type": "dh.setBlendshape", "target": "Body", "blendshape": "smile", "value": 0.75}dh.setTransform
Section titled “dh.setTransform”Set position, rotation, and/or scale on an object. Only the properties you specify are changed.
| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.setTransform" | yes | |
target | string | yes | Target object path |
position | [x, y, z] | no | Position in local space |
rotation | [x, y, z] | no | Rotation in degrees (Euler) |
scale | number or [x, y, z] | no | Scale (single number = uniform) |
{ "$type": "dh.setTransform", "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.setTransform", "target": "Glasses", "scale": 1.1}dh.setParent
Section titled “dh.setParent”Move an object under a new parent in the hierarchy.
| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.setParent" | yes | |
target | string | yes | Object to reparent |
parent | string | yes | New parent object path |
first | bool | no | If true, makes it the first child (default: false) |
{ "$type": "dh.setParent", "target": "HairAccessory", "parent": "Head", "first": true}dh.setRig
Section titled “dh.setRig”Apply a dh.rig definition to an armature, mapping standard bone names to model-specific bone names.
| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.setRig" | yes | |
target | string | yes | Armature/skeleton root path |
path | string | yes | Rig definition path (relative or barcode) |
mesh | string | no | Hierarchy path to the target SkinnedMeshRenderer for visemes/eyelids |
{ "$type": "dh.setRig", "target": "Armature", "path": "rigs/humanoid.dh-rig", "mesh": "Body"}dh.armatureLink
Section titled “dh.armatureLink”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.
| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.armatureLink" | yes | |
target | string | yes | Target armature path (must have a rig applied via dh.setRig) |
source | string | yes | Source object or armature path |
bone | string | no | Target bone name (required for rig-less sources) |
align | bool | no | Align source transform with target bone (default: true) |
Bone-to-bone example:
{ "$type": "dh.armatureLink", "target": "Armature", "source": "OutfitArmature"}Single-bone attachment:
{ "$type": "dh.armatureLink", "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.
dh.setSpringBones
Section titled “dh.setSpringBones”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.
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
$type | "dh.setSpringBones" | yes | ||
target | string | yes | Path to the root bone of the chain | |
ignore | string[] | no | Child transform names to exclude (along with their descendants) | |
stiffness | float | no | 0.3 | Pull toward animated pose (0 = floppy, 1 = locked) |
damping | float | no | 0.7 | Oscillation decay (0 = bouncy, 1 = no motion) |
gravity | float | no | 0.0 | Downward pull strength in world space |
{ "$type": "dh.setSpringBones", "target": "Body/Armature/Tail1", "stiffness": 0.2, "gravity": 0.3}Multiple chains on the same avatar:
// In the patches array:{ "$type": "dh.setSpringBones", "target": "Body/Armature/Tail1", "stiffness": 0.2, "gravity": 0.3 },{ "$type": "dh.setSpringBones", "target": "Body/Armature/EarL1" },{ "$type": "dh.setSpringBones", "target": "Body/Armature/EarR1" }Excluding specific children:
{ "$type": "dh.setSpringBones", "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.