Light
Adds a light source to an entity. The entity's world transform determines the light's position (point) or direction (directional). Point light positions are auto-synced from that world transform, so a light on a child entity burns where the entity stands — the position `entity.po…
Light
Adds a light source to an entity. The entity's world transform determines the light's position (point) or direction (directional). Point light positions are auto-synced from that world transform, so a light on a child entity burns where the entity stands — the position entity.position reports. A point light's intensity is on one scale with the SpotLight component's intensity/brightness: the same number at the same radius/range puts the same light on a surface either kind faces from the same place, and a spot spends it on the cone it opens on rather than all around itself.
Kinds: "point", "spot", "directional" (the scene's sun), "ambient", "distant" (a parallel light beside the sun).
Public fields: kind, colorR/G/B, intensity, radius, directionX/Y/Z, castsShadows, lightChannels, mobility. range, color and direction are aliases accepting the composite/renamed forms.
Methods: :setColor(color) (color: {r, g, b} array or {r=, g=, b=} map), :setIntensity(i), :setRadius(r), :setDirection(dir), :setKind(lightKind).
kind = "spot" opens a cone along the entity's forward axis, at the engine's default 30° outer and 20° inner half-angles; the SpotLight component is the one that carries the cone angles and the face axis as fields. "directional" and "distant" are parallel lights: they arrive from the same direction at every point in the world and no distance attenuates them, so their intensity reads against the sun's rather than against a point light's. The SpotLight README carries the rest of how to balance a mixed point-and-spot rig.
entity(id).component.add("Light", { kind = "point", intensity = 2, radius = 10 })
entity(id).component.add("Light", { kind = "directional", direction = {-0.5, -1, -0.3} })
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
conforms to
zero/source-extract/v2Light Component Adds a light source to an entity. The entity's world transform determines the light's position (point) or direction (directional). A point light's `intensity` is on one scale with the SpotLight component's `intensity`/`brightness`: the same number at the same `radius`/`range` puts the same light on a surface either kind faces from the same place, and a spot spends it on the cone it opens on rather than all around itself. Point light positions are auto-synced from that world transform by the engine — no manual position updates needed. A light on a child entity burns where the entity stands, at the position `entity.position` reports. Kinds: "point" — Emits light in all directions from entity position. "spot" — A cone along the entity's forward axis, at the engine's default 30° outer and 20° inner half-angles. The SpotLight component carries the cone angles and the `face` axis as fields. "directional" — Sets the scene directional light direction + color. "ambient" — Sets the scene ambient light color + intensity. "distant" — A parallel light beside the sun, one row of the scene's light buffer. It arrives from the same direction at every point in the world and no distance attenuates it, so its `intensity` reads against the sun's rather than against a point light's. Lights cast shadows by default (`castsShadows`); set it `false` to keep a light purely additive. Directional lights drive the scene's cascaded shadow map. Point lights cast omnidirectional (cube) shadows on the surrounding geometry; the capacity is capped, so past the cap a light stays lit but unshadowed. Config is the native Light ECS component, driven through the typed ecs.Light API. Color is stored as the `colorR`/`colorG`/`colorB` channels; `radius`, `kind`, and `directionX/Y/Z` hold the rest. The `color`, `range`, and `direction` aliases accept the natural composite/renamed forms at `component.add` time and route to those fields. Usage: entity.find("lamp").component.add("Light", { kind = "point", color = {1, 0.8, 0.5}, intensity = 2, range = 10 }) entity.find("sun").component.add("Light", { kind = "directional", direction = {-0.5, -1, -0.3} }) entity.find("scene").component.add("Light", { kind = "ambient", intensity = 0.3 })
isBakedState( ) → void
capitalize(s: ?) → void
| arg | type | description |
|---|---|---|
| s | ? |
contributionWithheld( ) → void
A baked static light contributes nothing live: the baked artifacts already carry all of it, so realtime light would double it and its shadow map would re-render every frame for nothing. A mixed light keeps its direct light and shadows — only its bounce is baked.
lightValue( ) → void
Build the typed ecs.Light value from the public fields. lightType takes the capitalized LightType variant ("Point" / "Directional" / "Ambient" / "Distant"). A withheld light keeps its row and zeroes what the row carries. The row is how the scene states that it has a light of this kind at all, and other systems read that: with the row gone, a procedural sky takes the absent sun as its cue to drive the scene's directional light itself.
componentIsLive( ) → boolean
Bring the live row to match the component. Idempotent, so re-entrant property notifications can't double-insert. Whether this component is running: its own switch is on, and the entity carrying it is active in the hierarchy. A component that is not running holds no row — `onDisable` and the active cascade each take it out — so a write that lands while it is off changes the authored value and nothing else, and `onEnable` builds the row back from whatever the fields hold by then. Read guarded: an entity mid-teardown answers nothing.
refreshRow( ) → void
applyAuthored( ) → void
Apply an authored change, un-baking first. Public setters route through this so editing a baked light restores its live contribution.
publishSunHolder( ) → void
Tell the lighting module whether THIS light is the scene's sun. A light is a component, so the component is what knows: nothing else should have to scan the scene to find the directional one, and the readers that ask every frame (atmosphere, fog, contact shadows, IBL, volumetrics) get a lookup instead.
retractSunHolder( ) → void
Give up the claim, but only if it is still ours: another directional light may have registered since, and clearing it then would blank a sun this component never held.
awake( ) → void
onEnable( ) → void
onDisable( ) → void
onPropertyChanged(key: ?, value: ?, oldValue: ?) → void
| arg | type | description |
|---|---|---|
| key | ? | |
| value | ? | |
| oldValue | ? |
onDestroy( ) → void
resolveMobility( ) → string
Resolve this light's mobility to `"static"`, `"mixed"` or `"dynamic"` — how GI baking treats it. An explicit `mobility` field wins; `"auto"` resolves to `"dynamic"` for a light something carries (non-world participation, an animated or physics-driven entity) and `"mixed"` for the rest. `"static"` bakes the light whole — direct light and bounce — and withholds its live contribution, so it costs nothing per frame and lights nothing that was not there at bake time. `"mixed"` bakes only its bounce and keeps its direct light and shadows live, so it still lights and shadows anything that moves. This is what `"auto"` picks, because a light that stands still still shines on characters walking under it. `"dynamic"` keeps the light out of the bake entirely.
examples
local mob = light:resolveMobility()
lightMobility( ) → string
How GI baking should treat this light, resolved to `"static"`, `"mixed"` or `"dynamic"`. Every component that puts a light in the scene answers this, which is how a bake finds the lights it has to account for without knowing what component authored them.
examples
if light:lightMobility() == "dynamic" then ... end
setColor(color: table) → void
Set the light color. Values >1 are auto-scaled from 0..255.
| arg | type | description |
|---|---|---|
| color | table | `{r, g, b}` array or `{r=, g=, b=}` map. |
examples
light:setColor({1, 0.8, 0.5})light:setColor({r = 255, g = 200, b = 128})setIntensity(i: number) → void
Set the light intensity (0..N).
| arg | type | description |
|---|---|---|
| i | number | Intensity scalar. |
examples
light:setIntensity(2.5)
setRadius(r: number) → void
Set the radius (point lights only).
| arg | type | description |
|---|---|---|
| r | number | Radius in world units. |
examples
light:setRadius(15)
setDirection(dirOrX: table | number, y: number?, z: number?) → void
Set the direction vector (directional lights only). Accepts three numbers or a single `{x, y, z}` / `{x=, y=, z=}` vector.
| arg | type | description |
|---|---|---|
| dirOrX | table | number | Either the x component, or a `{x, y, z}` array / `{x=, y=, z=}` map. |
| y | number? | The y component when the first argument is a number. |
| z | number? | The z component when the first argument is a number. |
examples
light:setDirection(-0.5, -1, -0.3)
light:setDirection({-0.5, -1, -0.3})setKind(lightKind: string) → void
Switch the light kind ("point" / "directional" / "ambient" / "distant"). `"directional"` aims the scene's sun, which is a single field: setting it replaces whatever the sun was. `"distant"` is parallel light held as a row of the scene's light buffer, so several coexist — `DirectionalLight` is the component that authors one.
| arg | type | description |
|---|---|---|
| lightKind | string | One of `"point"`, `"directional"`, `"ambient"`, `"distant"`. |
examples
light:setKind("directional")setCastsShadows(b: boolean) → void
Enable or disable shadow casting. Point lights cast omnidirectional (cube) shadows; spot lights cast a single projected shadow. Capacity is capped per kind — past the cap the light stays lit but unshadowed.
| arg | type | description |
|---|---|---|
| b | boolean | `true` to cast shadows, `false` to disable. |
examples
light:setCastsShadows(true)
Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
Problems
Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.
agent_score is exposed.+ quality × 0.35
+ performance × 0.25
± compat factor
Usability ratings
Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".
Scoped to this part · feeds back into the world's score.