Pallets & Assets
DigitalHeaven organizes everything into pallets — packages of related assets like avatars, materials, textures, and models.
Pallets
Section titled “Pallets”A pallet is a folder with a pallet.dh manifest and whatever assets it needs.
Pallet IDs
Section titled “Pallet IDs”Pallets use reverse-DNS identifiers:
io.mltn.mltn-mayutech.azuki.mayucom.example.my-avatar
This prevents naming conflicts and shows ownership. The ID also determines the folder path: io.mltn.mltn-mayu lives at Pallets/io.mltn/mltn-mayu/.
Manifest: pallet.dh
Section titled “Manifest: pallet.dh”Every pallet needs a manifest:
{ "id": "io.mltn.mltn-mayu", "name": "Mayu", "version": "1.0.0", "author": "mltn", "dependencies": { "tech.azuki.mayu-base": "^2.0.0" }}Assets
Section titled “Assets”An asset is any file inside a pallet — definition files (.dh-avatar, .dh-mat, etc.) or binary resources (.png, .glb, .wav).
Referencing Assets
Section titled “Referencing Assets”Within the same pallet — just use the relative path:
{ "texture": "textures/body-diffuse.png"}Across pallets — prefix with the pallet ID and a : separator:
{ "baseMesh": "tech.azuki.mayu:models/body.glb"}This is called a barcode: pallet.id:path/to/asset.
Resolution Rules
Section titled “Resolution Rules”- No
:in the path → local reference within the current pallet - Has
:→ everything before it is the pallet ID, everything after is the path - Paths are relative to the pallet root
Inheritance
Section titled “Inheritance”Assets can inherit from other assets — even across pallets — and override specific properties.
{ "inherits": "io.mltn.mltn-mayu:avatar.dh-avatar", "patches": [ // Only the patches that differ { "$type": "dh.set-material", "target": "Body", "slot": 0, "path": "materials/custom-skin.dh-mat" } ]}Inheritance works at every level: avatars, objects, materials, rigs. You only define what’s different.
The compiler resolves all inheritance chains at build time — the compiled output has everything flattened, no unresolved references.
Platform Overrides
Section titled “Platform Overrides”Platform-specific data lives in a platforms/ subdirectory alongside your universal definitions:
my-avatar/├── avatar.dh-avatar # Universal├── materials/│ └── skin.dh-mat # Universal material└── platforms/ ├── vrchat/ │ └── avatar-descriptor.jsonc ├── unity/ │ └── materials/ │ └── skin.dh-mat # Unity-specific shader overrides └── resonite/ └── avatar-metadata.jsoncWhen building for a platform, the compiler loads the universal definition first, then applies any matching overrides from platforms/{platform}/.
Organizing Your Pallet
Section titled “Organizing Your Pallet”Shared assets go in type-based folders at the pallet root. Self-contained features (accessories, outfits) get their own subdirectory with everything co-located:
my-pallet/├── pallet.dh├── avatar.dh-avatar├── textures/ # Shared textures│ ├── body-diffuse.png│ ├── body-normal.png│ └── body-orm.dh-tex├── models/ # Shared models│ └── body.glb├── rigs/ # Shared rigs│ └── humanoid.dh-rig├── materials/ # Shared materials│ ├── skin.dh-mat│ └── eyes.dh-mat└── accessories/ # Self-contained features ├── glasses/ │ ├── glasses.dh-obj │ ├── model.glb │ ├── material.dh-mat │ └── lens.png └── piercing/ ├── piercing.dh-obj ├── model.glb └── material.dh-matThe rule: shared/base assets in type folders at root; self-contained features get their own directory with everything they need inside.
Version Control
Section titled “Version Control”Designed for Git:
- Commit:
Pallets/(your source files) - Ignore:
Build/(generated output),.dh/(cache)
The workspace init generates .gitignore and .gitattributes automatically. The .gitattributes file sets up Git LFS for binary assets (.glb, .fbx, .png, .jpg, etc.) — make sure you have Git LFS installed if you’re using those.