skills/lighting-environment/SKILL.md
Dynamic lighting and environment in Decentraland scenes. LightSource (point and spot lights), shadows, SkyboxTime (day/night cycle), realm detection, and emissive materials for glow effects. Use when the user wants lights, shadows, skybox control, day-night cycle, or glowing materials. Do NOT use for PBR material properties like metallic/roughness (see advanced-rendering).
npx skillsauth add dcl-regenesislabs/opendcl lighting-environmentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
LightSource is supported in main-entities.ts — declare the lamp's fixture model AND its light in the same entry. The user can drag the fixture in the editor and the light follows.
// main-entities.ts
import type { Scene } from '@dcl/sdk/scene-types'
export const scene = {
ceiling_lamp: {
components: {
Transform: { position: { x: 8, y: 3, z: 8 } },
GltfContainer: { src: 'models/lamp.glb' },
LightSource: {
type: { $case: 'point', point: {} },
color: { r: 1, g: 1, b: 1 },
intensity: 16000
}
}
}
} satisfies Scene
For purely decorative lights with no mesh, declare a Transform-only entity and skip GltfContainer. Toggling lights at runtime still happens in src/index.ts via LightSource.getMutable(getEntityOrNullByName('ceiling_lamp')).
Emit light in all directions from a position:
// main-entities.ts entry
ambient_point: {
components: {
Transform: { position: { x: 8, y: 3, z: 8 } },
LightSource: {
type: { $case: 'point', point: {} },
color: { r: 1, g: 1, b: 1 },
intensity: 16000 // candela — point lights typically need 8000–32000 to be visible
}
}
}
LightSource.create(light, {
type: LightSource.Type.Point({}),
color: Color3.create(1, 0.5, 0), // Warm orange
intensity: 12000,
range: 15 // Maximum distance in meters
})
Emit a cone of light in a direction. The cone's orientation comes from the entity's Transform rotation.
// main-entities.ts
stage_spot: {
components: {
Transform: {
position: { x: 8, y: 4, z: 8 },
rotation: { x: -0.7071, y: 0, z: 0, w: 0.7071 } // pitch -90° (down)
},
GltfContainer: { src: 'models/spotlight.glb' },
LightSource: {
type: { $case: 'spot', spot: { innerAngle: 25, outerAngle: 45 } },
color: { r: 1, g: 1, b: 1 },
intensity: 16000
}
}
}
innerAngle — full-brightness cone angle (degrees)outerAngle — outer fade angle (degrees)Enable shadows on point or spot lights:
LightSource.create(spotlight, {
type: LightSource.Type.Spot({ innerAngle: 25, outerAngle: 45 }),
shadow: true,
intensity: 16000
})
Shadows are only available on spot lights, not point lights.
Project a pattern through the light:
const maskedLight = LightSource.getMutable(spotlight)
maskedLight.shadowMaskTexture = Material.Texture.Common({
src: 'assets/scene/images/lightmask1.png'
})
// Toggle on/off
const lightData = LightSource.getMutable(light)
lightData.active = !lightData.active
LightSource for both.Set a permanent time of day without code:
{
"skyboxConfig": {
"fixedTime": 36000
}
}
Time values: 0 = midnight, 36000 = noon, 54000 = dusk, 72000 = midnight again.
import { getWorldTime } from '~system/Runtime'
executeTask(async () => {
const time = await getWorldTime({})
console.log('Seconds since midnight:', time.seconds)
})
import { engine, SkyboxTime } from '@dcl/sdk/ecs'
// Set time of day (must target root entity)
SkyboxTime.create(engine.RootEntity, { fixedTime: 36000 }) // Noon
// Change with transition direction (TransitionMode from the generated protobuf)
SkyboxTime.createOrReplace(engine.RootEntity, {
fixedTime: 54000, // Dusk
transitionMode: 1 // TM_BACKWARD
})
let currentTime = 36000
const CYCLE_SPEED = 100 // Time units per second
function dayNightCycle(dt: number) {
currentTime = (currentTime + CYCLE_SPEED * dt) % 72000
SkyboxTime.createOrReplace(engine.RootEntity, {
fixedTime: currentTime
})
}
engine.addSystem(dayNightCycle)
Detect which realm (server) the player is connected to:
import { getRealm } from '~system/Runtime'
executeTask(async () => {
const realm = await getRealm({})
console.log('Realm:', realm.realmInfo?.realmName)
console.log('Network:', realm.realmInfo?.networkId)
console.log('Base URL:', realm.realmInfo?.baseUrl)
})
Material is supported in main-entities.ts, so a glow that doesn't need to cast light on surroundings can be declared inline:
// main-entities.ts
glowing_orb: {
components: {
Transform: { position: { x: 8, y: 1, z: 8 } },
MeshRenderer: { mesh: { $case: 'sphere', sphere: {} } },
Material: {
material: {
$case: 'pbr',
pbr: {
albedoColor: { r: 0, g: 0, b: 0, a: 1 },
emissiveColor: { r: 0, g: 1, b: 0 },
emissiveIntensity: 2.0
}
}
}
}
}
A single entity can carry both — emissive glow on the material AND light emission.
// main-entities.ts
bulb: {
components: {
Transform: { position: { x: 8, y: 3, z: 8 } },
GltfContainer: { src: 'models/bulb.glb' },
Material: {
material: {
$case: 'pbr',
pbr: {
emissiveColor: { r: 1, g: 0.9, b: 0.7 },
emissiveIntensity: 1.5
}
}
},
LightSource: {
type: { $case: 'point', point: {} },
color: { r: 1, g: 0.9, b: 0.7 },
intensity: 12000,
range: 10
}
}
}
Control shadow quality per light. Shadow type is set inside the Spot() or Point() helper:
import { LightSource, PBLightSource_ShadowType } from '@dcl/sdk/ecs'
// Spot light with soft shadows
LightSource.create(spotEntity, {
type: LightSource.Type.Spot({
innerAngle: 25,
outerAngle: 45,
shadow: PBLightSource_ShadowType.ST_SOFT
}),
shadow: true,
intensity: 16000
})
Available shadow types:
PBLightSource_ShadowType.ST_NONE — no shadows (cheapest)PBLightSource_ShadowType.ST_HARD — crisp shadows (medium cost)PBLightSource_ShadowType.ST_SOFT — smooth, blurred shadows (most expensive)Need advanced material effects? See the advanced-rendering skill for metallic, roughness, transparency, texture maps, and texture modes.
shadow on lights that don't need itrange on lights to limit their influence and save performanceSkyboxTime for atmosphere — nighttime scenes with point lights create dramatic environmentsdevelopment
Capture screenshots of the running Decentraland preview to verify scene changes visually. Covers camera movement, interaction actions, and visual debugging. Use when the preview is running and you need to check what the scene looks like, debug visual issues, or verify layout. Do NOT use for code changes (make changes first, then screenshot).
development
Cross-cutting runtime APIs for Decentraland SDK7 scenes. Use when the user needs async operations (executeTask), HTTP requests (fetch, signedFetch), WebSocket connections, timers, realm/scene detection, restricted actions (movePlayerTo, teleportTo, triggerEmote, openExternalUrl), portable experiences, or the testing framework. Do NOT use for UI (see build-ui), multiplayer sync (see multiplayer-sync), or avatar/player data (see player-avatar).
development
Apply physics forces to the player in Decentraland scenes. Impulses (one-shot pushes), knockback (push away from a point with falloff), continuous forces (wind tunnels, anti-gravity, lift, levitation, hover), timed forces, and repulsion fields. Use when the user wants launch pads, knockback on hit, wind zones, gravity fields, jumps, lifting/floating the player, pushing the player up/sideways/back, hover effects, or any scene-applied force on the player. THIS is also the right skill when an agent's first instinct is to mutate `Transform` on `engine.PlayerEntity` to move/lift/push the player — that does NOT work (the player Transform is engine-controlled and read-only); use the Physics API instead. Do NOT use for player movement speed (see player-avatar AvatarLocomotionSettings) or platform movement (see animations-tweens).
data-ai
Player and avatar system in Decentraland. Read player position/profile, customize appearance (AvatarBase), trigger emotes (triggerEmote/triggerSceneEmote), read equipped wearables (AvatarEquippedData), attach objects to players (AvatarAttach), create NPC avatars (AvatarShape), avatar modifier areas, and locomotion settings. Use when the user wants player data, emotes, wearables, NPC avatars, avatar attachments, or movement speed changes. Do NOT use for wallet/blockchain interactions (see nft-blockchain).