Pallets & Assets
DigitalHeaven organizes everything into pallets: packages of related assets like avatars, materials, textures, and models.
Naming Conventions
Section titled “Naming Conventions”One rule covers every identifier DigitalHeaven mints: dots separate namespaces, and every segment is camelCase. That applies uniformly — patch $types (dh.setMaterial), entity types (spawnPoint), input/output names (onPressed, open), and preference keys (world.jumpHeight, client.camera.roll.dampingRatio) all follow it. JSON property keys are camelCase too (baseMesh, eyeRotationLimits).
Acronyms are treated as ordinary words, never as all-caps runs: glbPath, setHdrSky, enableCsg — not GLBPath or enableCSG.
Hyphens still show up, but only where they’re structural rather than identifier style: file extensions (.dh-obj, .dh-mat), pallet IDs (io.mltn.avatars.mltn-mayu), and file paths. None of those are camelCase identifiers, so the hyphen stays.
Definition files (.dh-obj, .dh-mat, pallet.dh, etc.) are JSONC in practice: comments and trailing commas are accepted.
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.avatars.mltn-mayutech.azuki.avatars.mayucom.example.my-avatar
This prevents naming conflicts and shows ownership. The ID also determines the folder path: io.mltn.avatars.mltn-mayu lives at Source/io.mltn/avatars/mltn-mayu/.
Manifest: pallet.dh
Section titled “Manifest: pallet.dh”Every pallet needs a manifest:
{ "id": "io.mltn.avatars.mltn-mayu", "name": "mltn Mayu", "version": "0.0.1", "author": "mltn", "dependencies": { "tech.azuki.avatars.mayu": "^3.0.0" }}The manifest also accepts an optional look — a built-in slug or a .dh-look reference — which becomes the pallet’s house art direction. Every map in the pallet picks it up, and it is the weakest authored layer, so a map that names its own look or authors its own render fields still wins:
{ "id": "io.mltn.maps.nightcity", "name": "Night City", "version": "0.0.1", "look": "looks/night.dh-look"}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). The exception is sidecar files (e.g. sprite.png.dh-tex-settings), which carry import settings for a neighboring file and are consumed during compilation rather than included as assets. See dh.texture — Sidecar Files for details.
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.avatars.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.avatars.mltn-mayu:avatar.dh-avatar", "patches": [ // Only the patches that differ { "$type": "dh.setMaterial", "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:
Directorymy-avatar/
- avatar.dh-avatar Universal
Directorymaterials/
- skin.dh-mat Universal material
Directoryplatforms/
Directoryvrchat/
- avatar-descriptor.jsonc
Directoryunity/
Directorymaterials/
- skin.dh-mat Unity-specific shader overrides
Directoryresonite/
- avatar-metadata.jsonc
When 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:
Directorymy-pallet/
- pallet.dh
- avatar.dh-avatar
Directorytextures/ Shared textures
- body-diffuse.png
- body-normal.png
- body-orm.dh-tex
Directorymodels/ Shared models
- body.glb
Directoryrigs/ Shared rigs
- humanoid.dh-rig
Directorymaterials/ Shared materials
- skin.dh-mat
- eyes.dh-mat
Directoryaccessories/ Self-contained features
Directoryglasses/
- glasses.dh-obj
- model.glb
- material.dh-mat
- lens.png
Directorypiercing/
- piercing.dh-obj
- model.glb
- material.dh-mat
The 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:
Source/(your source files),Scripts/(your custom scripts) - Ignore:
Pallets/(compiled 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.), so make sure you have Git LFS installed if you’re using those.