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.
Properties
Section titled “Properties”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.
| Property | Type | Required | Description |
|---|---|---|---|
$type | "dh.look" | no | Type identifier |
name | string | no | Display name |
description | string | no | One line on what the look reproduces |
exposure | float | no | Linear multiplier applied to scene radiance before the curve. Must be > 0 |
tonemap | string | no | Curve name: reinhardWhite, aces, reinhard or none. Matched case-insensitively |
bloom | bool | no | Whether bright areas bloom at all |
bloomIntensity | float | no | Linear multiplier the resolved bloom pyramid is added back with. Must be ≥ 0 |
bloomThreshold | float | no | Linear radiance above which a pixel blooms, tested on its brightest channel. Must be ≥ 0 |
bloomSoftKnee | float | no | Width of the quadratic knee below the threshold, as a fraction of it. 0–1 |
bloomDiffusion | float | no | How far the bloom spreads, in pyramid levels rather than pixels. 1–10 |
bloomAnamorphic | float | no | Aspect distortion of the glow. -1–1; 0 is round, negative stretches vertically |
halfLambert | float | no | Diffuse wrap. 0–1: 0 is a hard Lambert terminator, 1 a full Source-style wrap |
falloff | string | no | Default point/spot distance curve: physical or unity |
The type is inferred from the file extension, so
$typeis 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.
Full Example
Section titled “Full Example”{ "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"}Adopting a look
Section titled “Adopting a look”A map’s top-level look field takes either a built-in slug or a reference to a .dh-look asset:
// 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-wide default
Section titled “A pallet-wide default”A pallet manifest can name a look of its own, and every map in the pallet picks it up:
{ "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.
Precedence
Section titled “Precedence”A look is a seed, never a lock. From weakest to strongest:
| # | Layer | Where it is authored |
|---|---|---|
| 1 | Engine defaults | The engine itself; whatever a look leaves unset falls through to here |
| 2 | Pallet default look | pallet.dh → look |
| 3 | Map’s look | the .dh-map’s look field (a slug or a .dh-look) |
| 4 | Map’s explicit fields | the .dh-map’s own render and lighting blocks |
| 5 | Live console edit | a 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.
Hot rebuild
Section titled “Hot rebuild”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.