Renderer · interface

AreaLightSource

One rectangular emitter, as a consumer describes it.

Explained in Hello world.

interface AreaLightSource
import type { AreaLightSource } from '@driftengine/core';

In depth

Positions, colours and sizes, and nothing that means anything in one game — the rule AGENTS.md opens with. right and up are the rectangle's own in-plane axes, and their cross product is the direction it emits.

Properties

NameTypeDescription
xnumber
ynumber
znumber
rnumber
gnumber
bnumber
rightXnumberIn-plane axes. Normalised on the way in, because the form factor assumes unit length.
rightYnumber
rightZnumber
upXnumber
upYnumber
upZnumber
halfWidthnumberHalf extents along right and up, in metres.
halfHeightnumber
twoSidedoptionalbooleanWhether the rectangle emits from both faces. Default false.
More

A window is one-sided and a hanging panel is two-sided, and the difference is visible rather than pedantic: a one-sided light must contribute nothing to a surface behind it, or the wall it is set into is lit by it and reads as glowing.

castsShadowoptionalbooleanWhether this rectangle is worth a shadow layer at all. Default false, which is the opposite of what a point light's identically named field defaults to.
More

A point light has cast since before there was a budget to ration, so true is what its existing callers already rely on. An area light shipped in 3.2.0 with no occlusion at all — AGENTS.md calls that a bug rather than a limitation, and it is the row this field closes — so every scene that already declares one was authored against a rectangle that lights through walls. Defaulting to true here would hand each of them two octahedral layers, 8.39 MB, and a six-face bake over the static world, for a change in the picture nobody asked for. RenderQuality's own rule is that a feature's default reproduces today's frame.

It also rides RenderQuality.pointShadows, because an area light's occlusion is read out of the same array texture a point light's is. WebGL2 guarantees sixteen texture units and the lit pass binds sixteen, so a seventeenth sampler is not available to declare — see FlatShaderOptions.environmentProbe for the same wall reached from the other side. With that flag off there is no array to bake into, and the renderer says so once by name rather than quietly drawing an unoccluded rectangle.

shadowRangeoptionalnumberHow far from the rectangle occlusion is tracked, in metres: the shadow map's far plane.
More

Required when castsShadow is true, and deliberately not defaulted. A point light's map gets its far plane from radius, the distance at which the light itself reaches zero — a rectangle has no such distance, because its falloff is the solid angle it subtends and that is never exactly zero. So the number is a statement about how much of the scene this fixture is responsible for occluding, which is a decision about the content: a panel in a corridor wants the corridor's length and a sky panel over a courtyard wants the courtyard's.

Guessing it would produce one of two failures, both of which read as a renderer bug rather than a missing field: too short and the shadow stops in a straight line partway across the floor, too long and the depth precision spent on the near metres is what a fixture actually needed. A rectangle that declares it casts and names no range is refused with a warning naming the field.

shadowNearoptionalnumberWhere casting begins, in metres from the rectangle's plane. Defaults to POINT_SHADOW_NEAR.
More

The same knob a point light carries and for the same reason: a fixture's own housing sits within centimetres of the emitter, occludes an enormous solid angle from it, and throws that across the floor as a hard square much larger than the housing. Keep it small — it clips every caster, not just the fixture.

rangeoptionalnumberHow far the rectangle's light reaches, in metres from its centre: past it the light is zero, windowed down to it, so a clustered rectangle can be binned into the froxels it reaches and no others. Read only where the rectangle is shaded through the froxel table — the ones past maxAreaLights with clusteredLights on; the fixed four light everything they face, as they always have. Absent, it is where the rectangle's irradiance on its axis falls to a thousandth of a scene unit, and never inside the rectangle itself. An attenuation radius, in metres.
barnDoorAngleoptionalnumberBarn doors: a flap hinged at each of the rectangle's four edges, standing this many degrees from its normal. 90, or absent, folds them flat and they hide nothing; smaller closes them, so the light narrows to the opening they leave — a rectangle at 50° throws a beam rather than filling its hemisphere. 88° is the usual default, nearly flat.
More

What a fragment sees past the doors is the part of the rectangle no door's tip hides, one axis at a time, and the rectangle then shades as that smaller rectangle, its highlight included. Its shadow map is still baked from the whole rectangle's centre. What it gives up: each door is taken as endless along its hinge, so the two axes clip apart and the corner where two doors meet hides a square rather than the mitre two real flaps make. One-sided: a two-sided rectangle's back face has none.

barnDoorLengthoptionalnumberThe barn doors' length in metres. Absent, 0.2: the usual default of 20 cm.