Skip to content

dh.look

Extension: .dh-look
Type ID: dh.look

A look is a named bundle of art direction a map adopts instead of transcribing numbers: the tonemap curve, the exposure, the bloom shape, the diffuse wrap and the light falloff. The engine ships three built-in looks by slug, and a .dh-look file is how you author your own — a house look you write once and every map in the pallet inherits.

A look carries the response chain and nothing else. It never touches your sun direction, your sun or ambient colors, or the intensity scales, because those describe a particular scene rather than a reusable look. A map ported with its source engine’s ambient values keeps them.

Every field is optional, and an omitted field means “this look does not speak to that setting” — it falls through to the engine default rather than being pinned. That is what makes a look composable.

PropertyTypeRequiredDescription
$type"dh.look"noType identifier
namestringnoDisplay name
descriptionstringnoOne line on what the look reproduces
exposurefloatnoLinear multiplier applied to scene radiance before the curve. Must be > 0
tonemapstringnoCurve name: reinhardWhite, aces, reinhard or none. Matched case-insensitively
bloomboolnoWhether bright areas bloom at all
bloomIntensityfloatnoLinear multiplier the resolved bloom pyramid is added back with. Must be ≥ 0
bloomThresholdfloatnoLinear radiance above which a pixel blooms, tested on its brightest channel. Must be ≥ 0
bloomSoftKneefloatnoWidth of the quadratic knee below the threshold, as a fraction of it. 01
bloomDiffusionfloatnoHow far the bloom spreads, in pyramid levels rather than pixels. 110
bloomAnamorphicfloatnoAspect distortion of the glow. -11; 0 is round, negative stretches vertically
halfLambertfloatnoDiffuse wrap. 01: 0 is a hard Lambert terminator, 1 a full Source-style wrap
falloffstringnoDefault point/spot distance curve: physical or unity

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

A value outside the range above is a compile error, not a silent clamp — and it is the same error, from the same validator, that the equivalent field in a map’s own render or lighting block would raise.

looks/night.dh-look
{
"name": "Night",
"description": "Cold, low-key interiors: ACES off, wide soft bloom, full diffuse wrap.",
"exposure": 1.4,
"tonemap": "reinhardWhite",
"bloom": true,
"bloomIntensity": 0.45,
"bloomThreshold": 1.1,
"bloomSoftKnee": 0.6,
"bloomDiffusion": 8,
"bloomAnamorphic": -0.24,
"halfLambert": 1.0,
"falloff": "physical"
}

A map’s top-level look field takes either a built-in slug or a reference to a .dh-look asset:

maps/lobby.dh-map
// A built-in slug...
"look": "unity"
// ...a look in this pallet...
"look": "looks/night.dh-look"
// ...or one from a dependency.
"look": "io.mltn.looks:looks/night.dh-look"

The built-in slugs are neutral, unity and source — see the map’s look table for what each reproduces.

Cross-pallet references follow the ordinary resolution rules: the core pallet is always available, and any other pallet ID must be a declared dependency in your pallet.dh.

A pallet manifest can name a look of its own, and every map in the pallet picks it up:

pallet.dh
{
"id": "io.mltn.maps.nightcity",
"name": "Night City",
"version": "0.0.1",
"look": "looks/night.dh-look"
}

This is the weakest authored layer, so it never fights a map that names its own. It is for the case a pallet’s maps all share a house look: state it once, in one place, rather than repeating it in every .dh-map.

A look is a seed, never a lock. From weakest to strongest:

#LayerWhere it is authored
1Engine defaultsThe engine itself; whatever a look leaves unset falls through to here
2Pallet default lookpallet.dhlook
3Map’s lookthe .dh-map’s look field (a slug or a .dh-look)
4Map’s explicit fieldsthe .dh-map’s own render and lighting blocks
5Live console edita stored world.render.* / world.lighting.* value

So a pallet whose default look is night, containing a map that adopts unity and then sets render.exposure, renders at that exposure, with the Unity curve and bloom, and picks up night only for fields both of the others leave unset. Nothing is ever written back to the map, and a console edit is a live override on top rather than an edit of the content.

Like materials, look definitions are re-read on every rebuild rather than cached against a checksum, so editing a .dh-look and recompiling applies on the next map load without restarting the engine.