@huukhanhnguyen/types / objects/light
objects/light
CylinderLight
CylinderLight = {
length:number;radius:number;shape:"cylinder"; }
A tube: an emitter extruded along its own axis, which is the direction the carrying document states.
length
length:
number
radius
radius:
number
shape
shape:
"cylinder"
DiskLight
DiskLight = {
radius:number;shape:"disk"; }
A downlight: a flat round emitter. Being flat, it has a FRONT, so it needs a direction on the document that carries it.
radius
radius:
number
shape
shape:
"disk"
LightData
LightData =
LightShape& {color?:string;coneAngle?:number;direction?:Vector;ies?:string;kelvin?:number;lumens:number;penumbra?:number;position:Point; }
Object-tier light datablock: ONE emitter — where it is, what shape emits, and what it radiates. There is no separate Light beside it, because there is only one shape and the law allows it only one name.
A light has no INTERNAL plurality, so it carries no Data-tier array (being an INDEPENDENT kind is a different question — point is independent yet its entries are a list). N is instances[]'s job — a rig of 12 identical bulbs is one LightData placed 12 times, never 12 entries in a list.
Photometric units, so an author states what a manufacturer prints on the box and a renderer converts to its own.
LightEntity
LightEntity =
LightData& {gizmoSize?:number;target?:Point; }
A light's Entity tier: its emitting core (LightData) plus what only a VIEWPORT needs to draw and aim it. A light has no internal plurality, so this is exactly ONE Entity and not an array (unlike PointEntity, which is a point of a cloud); N lights is instances[].
The two fields here are exactly what the functional core cannot say: lumens does not become a gizmo by living on the same document, and a photometric field is not made display data by being read by a renderer.
LightInstance
LightInstance =
BaseInstance& { }
A light has no surfaces; material is rejected on this kind.
LightObject
LightObject =
BaseObject& {data:LightEntity;instances:LightInstance[];type:"light"; }
An object whose data is lights and nothing else.
A light is an emitter, not a tessellatable body. Grouping emitters as their own kind gives a lighting consumer a DOMAIN instead of sniffing the stream for lumens. The housing is ordinary solid geometry on a different object.
LightShape
LightShape =
PointLight|SphereLight|DiskLight|RectangleLight|CylinderLight
The emitting shape. A tagged union because these are genuinely different geometry — a disk has a radius and a rectangle has two sides — not because a renderer happens to have a class per kind.
There is no spot arm, and its absence is the point: a spot is any shape with a coneAngle set, so narrowing stays ORTHOGONAL to what emits, and a disk-with-a-cone (a real downlight) is expressible. three.js's SpotLight class fuses the two and cannot say it.
PointLight
PointLight = {
shape:"point"; }
An emitter with no extent at all: the idealisation, and the right answer for a filament small against the room.
NOT the same subject as Point (geometry/core.ts), which is a bare [x, y, z] tuple — this is a light whose emitting shape is a single spot.
shape
shape:
"point"
RectangleLight
RectangleLight = {
height:number;shape:"rectangle";width:number; }
A panel or a window: a flat rectangular emitter, width × height. Flat, so it needs a direction too.
height
height:
number
shape
shape:
"rectangle"
width
width:
number
SphereLight
SphereLight = {
radius:number;shape:"sphere"; }
A bulb: an emitter with volume, so its edge shadows are soft in proportion to radius.
radius
radius:
number
shape
shape:
"sphere"