Dicey Table

LIGHT

LIGHT is one of the two optional Engine components (tone="engine") an author can add to a table object — the other is CAMERA. Unlike RENDER/RIGIDBODY/COLLISION, it is absent by default and only appears once added from + ADD COMPONENT (documented on inspector/add-component.md, not this page).

This is not the same thing as a Room Light. A Room Light (selectedNode.kind === "light") is a Platform concept that lights the whole scene and is documented on platform-panels.md. This page is the light engine component attached to one specific table object — e.g. a glowing die or a lamp prop that casts its own light. They use overlapping vocabulary (type, color, intensity, range) but are two different schemas, added through two different UIs, and neither replaces the other.

Source: LIGHT_FIELDS and the light descriptor in packages/shared/src/componentInspector.ts; schema in packages/shared/src/objectComponents.ts (objectLightComponentPropsSchema); runtime application in TabletopRuntime.applyObjectComponents.

Fields#

The panel is four blocks, separated by rules, in PlayCanvas's own order: the basics, the lightmap block, the shadow block, and Layers. Which fields appear depends on the Type and on the two block switches (Bake lightmap, Cast shadows) — a field that a light type ignores is not shown, because a knob that does nothing is worse than a missing one.

Each row is its label on the left, its control on the right. Where the tables below quote a field's hint, that text is the hover card: point at the field's label (or tab to it) and the card opens beside the Inspector. The hints are not printed under the controls — with 13 of them in this one section, the panel read as prose with controls embedded in it.

Everything here replicates as part of TableObjectState.components[].

Lengths are shown in your chosen unit. Every range and default below is quoted in world units (feet), which is how the file stores them. The field itself shows and reads whichever unit you picked in File ▸ Preferences — so a Range of 8 reads as 2438.4 with millimetres selected, and is still 8 in the file.

Basics#

Field Type Range / units Default Shown for Runtime effect
Type select Omni (point), Spot, Directional omni all omni is PlayCanvas's name for a point light (radiates in all directions). Spot is a cone. Directional has no meaningful position or range — only its orientation (inherited from the entity's transform) matters, like sunlight.
Color color hex #rrggbb #ffffff all The light's color.
Intensity slider 0–32, step 0.05 1 all Brightness multiplier.
Range number 0–200, step 0.5, world units (feet) 8 omni, spot Falloff distance. World units in DiceyTable are feet, not metres, so a Range of 8 reaches 8 feet.
Falloff mode select Linear, Inverse squared linear omni, spot How brightness decays over Range. Inverse squared is how light really falls off; linear is easier to art-direct.
Inner cone slider 0–90°, step 1 40 spot The angle within which the light is at full intensity.
Outer cone slider 0–90°, step 1 45 spot The angle at which the light falls off to zero. The runtime clamps outer to be at least inner — a crossed pair would render as a hard edge, so it is corrected rather than rejected.

Lightmap#

Only relevant on a table that has been baked (Room panel → Bake static lighting).

Field Type Range Default Shown for Runtime effect
Static boolean false all Promises the light never moves, so the renderer can stop re-deriving its influence. A light that does move still shades correctly — it just costs more than it claims to.
Bake lightmap boolean false all Bake this light into the lightmap instead of shading every frame.
Bake direction boolean true all, with Bake on Bake directional information: a better-lit normal-mapped result for twice the texels.
Bake samples number 1–255 1 all, with Bake on Samples per texel. 1 is a point sample and has no penumbra.
Bake area slider 0–180°, step 1 0 all, with Bake on Angular size of the emitter — the softness of a baked shadow's edge.
Affect lightmapped boolean false all Light geometry that has already been baked. Off by default, so a baked room is not lit twice.
Affect dynamic boolean true all Light geometry that is not baked — every moving piece. Off makes the light bake-only.
Affect specularity boolean true directional Contribute to specular highlights as well as diffuse. Off gives a flat, matte fill.

Shadows#

Every row below Cast shadows appears only while it is on.

Field Type Range Default Shown for Runtime effect
Cast shadows boolean false all The label's hover card: "Shadow-casting lights are the most expensive thing on the table. Use sparingly."
Update mode select Realtime, Once, None realtime all Once renders the shadow map on the next frame and freezes it — the right choice for a light over scenery that never moves.
Resolution select 256 – 4096 2048 all Shadow-map edge length. Powers of two only: the map is square and allocated at this size, so an in-between number would cost the memory of the next size up and look like the one below.
Cascades select 1–4 1 directional Sharper shadows near the camera. Each cascade is another shadow view, and the room budget counts views — a 4-cascade sun costs four times what a 1-cascade one does.
Distance number 0.1–400, feet 14 directional How far from the camera shadows are drawn. Omni and spot lights ignore this entirely — their shadow extent is Range — so the field is not offered for them.
Shadow intensity slider 0–1, step 0.01 1 all 0 casts no visible shadow; 1 is fully dark.
Shadow type select PCF 1x1 through PCSS (soft) pcf3 all The filter. PCSS is the soft, contact-hardening one. An omni light is offered only PCF 1x1, PCF 3x3 and PCSS: it renders a cube map, and the engine refuses VSM on one — rewriting it to pcf3 without saying so.
Soft samples slider 1–64, step 1 16 all, with Shadow type PCSS Shadow samples per pixel. Smoother, and more expensive, as it rises.
Blocker samples slider 0–64, step 1 16 all, with Shadow type PCSS What makes the shadow hard where the piece touches the table and soft as it lifts away. 0 turns contact hardening off and gives a shadow of constant softness; safe to keep below Soft samples.
Penumbra size slider 0–32, step 0.1 1 all, with Shadow type PCSS How big the light is. A bigger light throws a wider, softer penumbra.
Penumbra falloff slider 1–16, step 0.1 1 all, with Shadow type PCSS How quickly the shadow softens with distance. 1 is a linear opening; higher softens sooner.
Shadow bias slider 0–1, step 0.01 0.05 all Depth offset that stops a surface shadowing itself. Raise to kill shadow acne; raise too far and the shadow detaches from its caster.
Normal offset bias slider 0–1, step 0.005 0.03 all Offset along the surface normal. The gentler of the two acne fixes — try this before Shadow bias.

Soft shadows (PCSS)#

PCSS is the one shadow filter whose cost lands per pixel, every frame rather than in the shadow map. That is the opposite trade to Resolution, which is free here (the map is draw-call bound, not fill bound), and it is why the four PCSS rows only appear once the filter is selected.

The stock table's Key Light ships with PCSS on. It can afford it because the table has exactly one shadow-casting light and its shadow map is already gated to redraw only when something moves, so the soft filter is the only shadow cost being paid. A room that adds several shadow casters should not assume the same.

Two things happen to PCSS outside your control, and neither writes anything back to the room — the document keeps saying pcss, so the light comes back soft wherever it can:

  • On a device that cannot render it, the engine falls back to PCF 3x3. PCSS needs a float-renderable, float-filterable shadow target; a device without one gets the sharp filter rather than a broken one.
  • On the Medium and Low graphics tiers, DiceyTable itself downgrades it to PCF 3x3. Medium is where phones and older laptops land, and they are the devices that render shadows and would feel the per-pixel cost. High and Ultra render it as authored.

Layers#

Field Type Default Runtime effect
Layers checkboxes: Scene, Table, Game all three Which render layers this light reaches. A lamp set to Scene + Table warms the room without washing out the card art in front of it.

Clearing every box leaves the light on, shining on nothing — a legal state the runtime honours rather than reinterpreting as "all", because otherwise the field could never be cleared. If a light stops doing anything, check Layers before Intensity.

The editor's own overlays are never affected: gizmos, markers and the collider wireframe live on the engine's World layer, which every light always reaches.

Where the defaults come from#

Three of them are DiceyTable's, not PlayCanvas's, and each was measured:

  • Resolution 2048 (engine default 1024) — measured free, and the reason the table's shadows are not mushy.
  • Distance 14 (engine default 16) — the table plus a comfortable margin, in feet. World units here are feet, so the engine's number is not the same distance it would be in a metres project.
  • Normal offset bias 0.03 (engine default 0) — tuned against a card stack, which is the thinnest shadow caster on the table and the first thing to show acne.

They are recorded with their reasoning in packages/shared/src/lightProperties.ts.

The component header#

Like every optional component, LIGHT's header carries:

  • An enable checkbox (component.enabled, default true on add) — disabling keeps the component's settings in the document without removing it, PlayCanvas's own recommended pattern.
  • A kebab menu with Disable/Enable, Reset to default, and Remove component… (which prompts for confirmation and discards the settings — disabling is the reversible alternative).

Both are inspector/add-component.md's to document in full; noted here only so this page's field table is read in context.

What the runtime actually applies#

TabletopRuntime.applyObjectComponents adds/updates/removes a real pc.LightComponent on the Live Entity to match, through the shared mapping in apps/web/src/playcanvas/rendering/applyLightProps.ts.

That mapping is the same function the Room Light panel uses, and it decides what to write from the same LIGHT_TYPES_WITH_* sets the Inspector uses to decide what to show. So "the panel offers exactly what the engine consumes" is a structural fact here rather than a convention someone has to maintain: a field cannot become visible for a type the runtime ignores, because both read one list.

Shadow properties are written only while Cast shadows is on — a light that is not casting has no shadow map to configure — and every write is guarded against its current value, because several of PlayCanvas's light setters invalidate the shadow map and this function runs for every object on every snapshot.

An explicitly ticked Bake lightmap wins over the automatic split. Bake static lighting otherwise classifies lights by Cast shadows (shadow-casters stay realtime so pieces still cast onto the baked room; fill lights bake). Ticking the box is the explicit act that turns that guess off for one light.

See also#