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 settings, like Unity's quality shadows: 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'Unity's 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.
DistanceshadowCameraSize30Unity's Shadow Distance: how far from the camera shadows render, clamped 10–200. Every directional light's shadow box follows the active camera 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 camera — for every directional light

Directional lights are infinite suns, so — exactly like Unity — 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 active camera 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 camera simply stop casting, which is what the setting means.

That makes Distance a quality dial as much as a reach dial: it decides how much ground around the viewer shares the shadow texture. 30 suits most maps; racing maps with long sight lines might use 100200 with a 4096 map.

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 })

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