Skip to content

Lighting & shadows

Every map is lit by up to two kinds of light source:

  1. The environment sun — a built-in directional light configured in Scene Settings ▸ Sun. It is not an entity and never appears in the Hierarchy. Every map has one unless you turn it off.
  2. Light entities — game objects with a directionalLight, pointLight, or spotLight component, placed like any other object and freely scripted.

One sun = one shadow

If you place your own Directional Light entity, turn the environment sun off (Scene Settings ▸ Sun ▸ Enabled) — two suns mean doubled lighting and two overlapping shadow passes. New maps start with the environment sun off.

Scene Settings ▸ Shadows

Shadows are controlled per map in Scene Settings ▸ Shadows (also settable by the AI and scripts through setSceneSettings, or directly in the map JSON). These are scene-wide quality settings: they drive the environment sun and act as the defaults for every Directional Light entity — so they work no matter which kind of sun lights your map.

SettingJSON keyDefaultWhat it does
EnabledshadowsEnabledtrueMaster switch — gates the environment sun and every Directional Light entity.
TypeshadowType'soft'Hard/Soft shadows. soft = smooth, filtered edges (PCFSoft); hard = crisp single-tap edges — cheaper, a stylized look. Renderer-wide.
Map SizeshadowMapSize2048The environment sun's shadow texture resolution: 512, 1024, 2048, 4096. Higher = crisper edges, more GPU memory.
DistanceshadowCameraSize30Shadow Distance: how far from the player shadows render, clamped 4–200. Every directional light's shadow box follows the player's character at this radius. Bigger = shadows reach further but each shadow gets softer/blurrier, because the same texture is stretched over more ground. Raise Map Size to compensate.
shadowCameraNear0.5Start of the env sun's shadow depth range. JSON/AI only.
shadowCameraFar4 × DistanceEnd of the env sun's shadow depth range. JSON/AI only. Runtimes keep it at least 3 × Distance — smaller values would put the viewer outside the range and turn shadows off entirely.

Shadows follow the player — for every directional light

Directional lights are infinite suns, so where the light entity sits is irrelevant: only its rotation (the light direction) matters. Each directional light's shadow frustum is a box of ±Distance units centred on the player's character and re-centred every frame — in the editor, the play-test, exported standalone games, and published multiplayer alike. Walk, drive, or fly anywhere and shadows come with you; objects further than Distance from the character simply stop casting, which is what the setting means.

The box centres on the camera instead whenever there is no character to centre on: the editor's Scene view, a map that disables the built-in player without scripting one in its place, and any moment a script has taken the camera with camera.setType('scriptable') — a cutscene points somewhere the character is not, so following them there would shadow ground nobody is looking at.

That makes Distance a quality dial as much as a reach dial: it decides how much ground around the player shares the shadow texture. 30 suits most maps; racing maps with long sight lines might use 100200 with a 4096 map. Small values are deliberately usable, down to a floor of 4 — at 6 the box holds the character and a couple of metres of ground around them, which is about as tight as a real shadow stays useful.

Below that, a shadow map stops being the right tool: the box is still paying for a depth render of everything inside it, and everything inside it still casts, so a tight box is a travelling bubble of shadows rather than one shadow. That is what blob shadows are for.

Shadows from light entities

ComponentCasts shadowsCoverage
directionalLightcastShadow (per entity, gated by the scene's Shadows ▸ Enabled)Camera-following box (see above). The box half-size is the scene's Distance; the light's own shadowCameraSize (Inspector: Shadow Size, clear the field to reset) can only shrink it for crisper shadows over less ground — the scene Distance is always the outer cap.
spotLightalwaysThe spotlight's own cone.
pointLightcastShadow, default offOmnidirectional; the most expensive — use sparingly.
ts
// A scripted lamp: warm spot shadows over a doorway
setComponent('spotLight', { color: '#ffcc88', intensity: 3, angle: 0.6, penumbra: 0.4 })

// A sun with a TIGHTER shadow box than the scene Distance — crisper shadows over less ground
setComponent('directionalLight', { color: '#ffffff', intensity: 1.2, castShadow: true, shadowCameraSize: 20 })

// Longer shadow reach is a SCENE setting (the cap for every light):
scene.setEnvironment({ shadowCameraSize: 120 })

Blob shadows

A blob shadow is a soft dark disc on the ground beneath an object, drawn instead of a real cast shadow. It costs one transparent quad and one downward ray, against a shadow map's depth render of the caster plus per-pixel sampling on every surface the shadow might land on. It cannot take the object's shape — what it gives you is the part players actually read: this thing is standing there, and that is where it would land.

Add the blobShadow component to any entity. It finds its own ground, tilts to that surface, and fades out as the entity rises above it, so there is nothing to place and nothing to keep lined up:

FieldDefaultWhat it does
RadiusautoDisc radius in world units. Left empty it fits the entity's own footprint, so a model swapped for a bigger one keeps a disc that suits it.
Opacity0.4How dark the disc gets at the entity's base. Fully opaque reads as a hole in the floor rather than as shade.
Max Drop5How far below to look for ground, and the height the disc fades out over. Raise it for something that hovers; lower it to drop the shadow sooner on a jump.
ts
// A crowd of enemies that reads as grounded without a shadow pass each
setComponent('blobShadow', { opacity: 0.35 })

// A hovering drone: keep its shadow visible from higher up
setComponent('blobShadow', { radius: 0.8, maxDrop: 12 })

It draws while you edit, not just in play mode, so placing one is something you can see.

An entity can carry both a real cast shadow and a blob. If you want only the blob, turn the entity's own castShadow off — otherwise the two stack into one darker smear.

Players have their own, separately: the Shadow Distance ▸ Only player step in a player's graphics settings switches the shadow map off entirely and draws a disc under every player's character — everyone in the room, not just the one holding the mouse — fading them out at the same distance nameplates stop drawing at. That is a device setting rather than a property of your map: it applies to players only, never to your entities, and only on that step. Any other Shadow Distance draws no player discs at all.

Changing shadows from a script

Every Shadows setting is also live-settable at runtime through scene.setEnvironment — the same call that drives sky, fog, and lighting changes. It merges (send only what you change), applies instantly, and in multiplayer broadcasts to every client:

ts
// Nightfall when the boss spawns: darker world, tighter but crisper shadows
scene.setEnvironment({
  skyColor: '#0a0a14', ambientIntensity: 0.15, sunIntensity: 0.4,
  shadowCameraSize: 40, shadowMapSize: 4096,
})

// Cutscene over the whole arena — trade sharpness for reach, then restore
scene.setEnvironment({ shadowCameraSize: 200 })
scene.setEnvironment({ shadowCameraSize: 30 })

// Turn shadows off for a low-spec mode toggle
scene.setEnvironment({ shadowsEnabled: false })

Troubleshooting

  • No shadows at all in the editor, and no shadow setting does anything — check Editor Settings ▸ Shadow Quality: off disables shadow rendering for your editor only (a per-user preference saved in the browser — the Scene Settings panel shows a warning when it's active). Exports and multiplayer are unaffected by it.
  • No shadows at all — check Scene Settings ▸ Shadows ▸ Enabled, and that the environment sun is on (Sun ▸ Enabled) or an entity light has castShadow: true.
  • Shadows look soft/blocky — raise Map Size, or lower Distance (the texture covers less ground, so each shadow gets more pixels).
  • Striped or splotchy surfaces (shadow acne) — the engine ships tuned bias defaults; if you see acne on custom content, raise Map Size or reduce Distance rather than pushing intensity.

See also

  • Quality & performance — project-wide shadow ceilings: force hard shadows everywhere, cap Distance and Map Size, or limit how many light entities may cast at once.
  • Scripting basicssetSceneSettings and setComponent from scripts.