Skip to content

Surfaces

Every solid in a world is made of something. A material’s surface block says what, and from that one word the engine decides how much grip you have, which footsteps play, how heavy a prop cooked from it is, and whether a fall hurts.

A three-quarter view down a long dark plate, tiled end to end with differently colored material squares, with four colored catwalks running above it at stepped heights and a stair climbing to each

The picture is core:maps/surface-eval, the yard the engine ships for exactly this: fourteen plates in one row, hardest first, with six catwalks over them at heights chosen so each lane brings one or two more kinds into hurting range.

Fourteen, fixed — a map cannot invent a fifteenth. stone is the default, and a material with no surface block at all behaves as stone at full grip.

The mark is what the level editor’s inspector puts beside the kind on a material’s Surface card. They are 32×32 pixel art, shown here at 2×.

MarkKindFootsteps you actually hearSounds like, acoustically
stone surface mark stonestoneconcrete
metalmetalmetal
wood surface mark woodstone (fallback)wood
dirt surface mark dirtdirtgravel
grass surface mark grassgrassgrass
gravel surface mark gravelstone (fallback)gravel
sand surface mark sandstone (fallback)gravel
glass surface mark glassstone (fallback)glass
flesh surface mark fleshstone (fallback)generic
plastic surface mark plasticstone (fallback)generic
fabric surface mark fabricstone (fallback)carpet
snow surface mark snowstone (fallback)generic
ceramic surface mark ceramicstone (fallback)generic
ice surface mark icestone (fallback)generic

Only four footstep folders ship — stone, dirt, grass and metal — so four of the fourteen kinds sound distinct and the rest fall back to stone. The fallback is not silent about itself: the first step on a kind with no folder logs one warning on the audio channel, once per kind per process, and the resolution is cached so it never repeats. The other eleven plates in the yard differ in grip and in what a fall costs, not in sound.

The grip, density and hardness each kind carries are the surface preset table on the material page; preset and kind are authored independently, so a material can say it is ice while taking its numbers from somewhere else.

A footstep set is a folder of numbered variants: footsteps/<set>/<set>-N.wav, probed from -1 upward until one is missing, to a ceiling of eight. stone ships five. The engine picks a variant at random per step and avoids repeating the one before it.

Cadence and gain are driven by movement, not by the surface: a footfall every 2.2 m traveled, no steps below 1 m/s, and loudness ramping from half to full between that floor and 8 m/s — just under the 10.16 m/s sprint, so any sprint is at full gain and an ordinary 5.08 m/s walk sits in the middle. Jumping plays the same sample as a quiet scuff; landing plays it pitched down, deeper the harder the fall.

The same yard seen from the side: four catwalks stacked one above another over the plate strip, their heights read off two black-and-orange striped rulers

A landing’s severity is not the speed alone — it is impact speed × the ground’s hardness. Past client.feel.landingHurtValue (9.9) the landing hurts: a pain grunt layers on top of the thud and the fall-impact view punch takes its extra kick. One fall pays one grunt, so a drop that scrapes a wall on the way down and then lands still only hurts once.

Because hardness is a multiplier, soft ground genuinely cushions. Solving the threshold at the engine’s default world.gravity of 15.24 m/s² gives the drop each kind survives:

KindHardnessHurts atFree drop
metal0.9510.4 m/s3.6 m
stone0.911.0 m/s4.0 m
glass0.8511.6 m/s4.5 m
ceramic0.812.4 m/s5.0 m
ice0.616.5 m/s8.9 m
wood0.519.8 m/s12.9 m
plastic0.424.8 m/s20.1 m
gravel0.3528.3 m/s26.3 m
dirt0.249.5 m/s80 m
grass0.1566.0 m/s143 m
sand, flesh0.199.0 m/s322 m
fabric, snow0.05198 m/s1.3 km

That is the whole demonstration of the yard: from its tallest catwalk at 30 m, everything down to gravel hurts and everything softer than gravel does not, no matter how far you push it.

Landing audio itself clamps earlier and separately — 2 m/s is the floor below which a touchdown is silent, and 14 m/s (about a 6.4 m drop) is the loudest, deepest thud. A plain jump lands at its own launch speed of 5.08 m/s, so it is audible but faint.

The kind lives on the material, so the way to change what a floor is made of is to change the material under it — in the inspector, or in the .dh-material itself:

{
"id": "dev.example.materials.walkway",
"baseColor": "textures/walkway",
"surface": {
"preset": "metal",
"kind": "metal"
}
}

Both brushes and imported geometry carry it. A boxBrush takes the surface kind of its material like any other solid, which is why every plate in the yard is a brush — building it out of imported meshes would have proved something else. When a map cooks its collision from the render mesh (autoCollision: "mesh"), each collision triangle keeps the material of the render slot it came from, so the mover samples the right grip per triangle rather than one value for the whole map.

Water is not one of these. A water body is a water block, and the two are mutually exclusive on a sane material.