The site is under maintenance, so logging in is temporarily unavailable. All resources and the MCP still work.

AI Skills

Lighting that looks good

By Roblox Vibecoders · roblox-lighting

Use when setting up or changing the look of a Roblox game - time of day, sun and ambient light, shadows, fog and atmosphere, sky and clouds, post effects (bloom, color correction, depth of field, sun rays, blur), and PointLight/SpotLight/SurfaceLight - or making a scene look like day, night, horror, neon/cyberpunk or an interior. Covers LightingStyle and PrioritizeLightingQuality, which replaced Lighting.Technology.

Install it

Terminal
mkdir -p ~/.claude/skills/roblox-lighting && curl -fsSL https://robloxvibecoders.com/skills/roblox-lighting/SKILL.md -o ~/.claude/skills/roblox-lighting/SKILL.md

Skills in ~/.claude/skills work in every project. Put them in your project's .claude/skills folder to share them with your team.

What your AI reads

SKILL.md
---
name: roblox-lighting
description: Use when setting up or changing the look of a Roblox game - time of day, sun and ambient light, shadows, fog and atmosphere, sky and clouds, post effects (bloom, color correction, depth of field, sun rays, blur), and PointLight/SpotLight/SurfaceLight - or making a scene look like day, night, horror, neon/cyberpunk or an interior. Covers LightingStyle and PrioritizeLightingQuality, which replaced Lighting.Technology.
---

# Lighting that looks good

Lighting is set on the `Lighting` service and its children (`Atmosphere`, `Sky`, post effects). Most of a scene's
mood comes from five things: time of day, sun brightness, ambient colors, atmosphere and color correction.

## The lighting system (current)

`Lighting.Technology` is **deprecated**. Since Unified Lighting (fully live July 2025) the engine uses two
properties, set in Studio's Properties window:

- `LightingStyle`: `Realistic` (detailed shadows and shading) or `Soft` (flatter, diffused shadows, the classic
  Roblox look).
- `PrioritizeLightingQuality`: `true` keeps lighting quality as devices scale down (draw distance drops first);
  `false` drops lighting quality first.

Old values were mapped: Future = Realistic + true, ShadowMap = Soft + true, Voxel = Soft + false. Compatibility was
retired in 2024; for that old look add a `ColorGradingEffect` with `TonemapperPreset = Enum.TonemapperPreset.Retro`.

## Lighting properties

| Property | What it does |
|---|---|
| `ClockTime` | hours, 0 to 24 (14 = afternoon, 18 = sunset, 0 = midnight). `TimeOfDay` is the same as a string |
| `GeographicLatitude` | changes the sun's path |
| `Brightness` | intensity of the sun or moon |
| `Ambient` | color of areas hidden from the sky (indoors, under roofs). Default black |
| `OutdoorAmbient` | color of outdoor areas. Default 127, 127, 127. Kept at or above `Ambient` |
| `EnvironmentDiffuseScale` | 0 to 1, ambient light from the sky that follows time of day. Raise it, lower `Ambient`/`OutdoorAmbient` |
| `EnvironmentSpecularScale` | 0 to 1, sky reflections on smooth and metal surfaces |
| `ExposureCompensation` | -5 to 5; +1 doubles exposure, -1 halves it |
| `GlobalShadows` | sun/moon shadows and the indoor/outdoor split. Off = flat lighting |
| `ShadowSoftness` | 0 (hard) to 1 (soft), with `LightingStyle = Realistic` |
| `FogStart`, `FogEnd`, `FogColor` | classic fog. Hidden and replaced when an `Atmosphere` exists |

## Atmosphere, sky and clouds

- `Atmosphere` (child of Lighting): `Density` (how much distant things fade), `Offset` (higher = horizon
  silhouette, lower = distant objects blend into the sky), `Color`, `Decay`, `Haze`, and `Glare` (only visible when
  `Haze` > 0).
- `Sky` (child of Lighting): `SkyboxBk/Dn/Ft/Lf/Rt/Up` (or the `...Content` versions), `SunAngularSize`,
  `MoonAngularSize`, `StarCount`, `CelestialBodiesShown`, `SkyboxOrientation`.
- `Clouds`: only render when parented to `workspace.Terrain`. `Cover` 0 to 1, `Density`, `Color`.

## Post effects

Children of `Lighting` apply to everyone; children of `workspace.CurrentCamera` (made by a LocalScript) apply to
that player only, for menus, damage flashes or underwater.

- `BloomEffect`: `Intensity`, `Size`, `Threshold` (lower threshold = more things glow).
- `ColorCorrectionEffect`: `Brightness`, `Contrast`, `Saturation`, `TintColor`.
- `DepthOfFieldEffect`: `FocusDistance`, `InFocusRadius`, `NearIntensity`, `FarIntensity`.
- `SunRaysEffect`: `Intensity`, `Spread` (keep 0 to 1).
- `BlurEffect`: `Size`. Use it for menus, not gameplay.
- `ColorGradingEffect`: `TonemapperPreset` (`Default` or `Retro`).

## Local lights

`PointLight` (sphere), `SpotLight` (cone: `Angle`, `Face`) and `SurfaceLight` (from one face: `Angle`, `Face`).
All have `Brightness` (default 1), `Color`, `Range`, `Shadows` and `Enabled`. `Range` is clamped to **120 studs**.
Lights must be a direct child of a `BasePart` or an `Attachment`; on an attachment, `Face` picks an axis (-Z is front).

Shadow-casting lights cost the most. Turn `Shadows` on only for a few key lights (a flashlight, the main lamp in a
room), never for every street light or neon strip.

## Recipes

Each recipe is a function you can run from a server Script or the command bar. Set `LightingStyle` and
`PrioritizeLightingQuality` in Studio first (Realistic + true for all of these unless noted).

```luau
local Lighting = game:GetService("Lighting")

local function ensure(className: string): Instance
	local object = Lighting:FindFirstChildOfClass(className)
	if not object then
		object = Instance.new(className)
		object.Parent = Lighting
	end
	return object
end

local function apply(settings: { [string]: { [string]: any } })
	for target, props in settings do
		local object: any = if target == "Lighting" then Lighting else ensure(target)
		for name, value in props do
			object[name] = value
		end
	end
end

local rgb = Color3.fromRGB

local DAY = {
	Lighting = { ClockTime = 14, Brightness = 3, Ambient = rgb(40, 40, 45), OutdoorAmbient = rgb(128, 128, 128),
		EnvironmentDiffuseScale = 1, EnvironmentSpecularScale = 1, ExposureCompensation = 0, GlobalShadows = true,
		ShadowSoftness = 0.2 },
	Atmosphere = { Density = 0.3, Offset = 0.25, Color = rgb(199, 199, 199), Decay = rgb(106, 112, 125), Glare = 0, Haze = 0 },
	BloomEffect = { Intensity = 0.5, Size = 24, Threshold = 2 },
	SunRaysEffect = { Intensity = 0.05, Spread = 0.6 },
	ColorCorrectionEffect = { Brightness = 0, Contrast = 0.05, Saturation = 0.05, TintColor = rgb(255, 255, 255) },
}

local NIGHT = {
	Lighting = { ClockTime = 0, Brightness = 1, Ambient = rgb(20, 22, 32), OutdoorAmbient = rgb(45, 50, 75),
		EnvironmentDiffuseScale = 0.3, EnvironmentSpecularScale = 0.5, ExposureCompensation = 0 },
	Atmosphere = { Density = 0.35, Offset = 0.1, Color = rgb(60, 70, 100), Decay = rgb(30, 35, 60), Glare = 0, Haze = 0.5 },
	BloomEffect = { Intensity = 0.8, Size = 30, Threshold = 1.2 },
	ColorCorrectionEffect = { Brightness = 0, Contrast = 0.1, Saturation = -0.1, TintColor = rgb(225, 235, 255) },
	Sky = { StarCount = 3000 },
}

local HORROR = {
	Lighting = { ClockTime = 0, Brightness = 0, Ambient = rgb(6, 6, 8), OutdoorAmbient = rgb(18, 18, 22),
		EnvironmentDiffuseScale = 0.1, EnvironmentSpecularScale = 0.3, ExposureCompensation = -0.5 },
	Atmosphere = { Density = 0.55, Offset = 0, Color = rgb(40, 40, 45), Decay = rgb(20, 20, 25), Glare = 0, Haze = 3 },
	BloomEffect = { Intensity = 0.3, Size = 20, Threshold = 2 },
	ColorCorrectionEffect = { Brightness = -0.05, Contrast = 0.2, Saturation = -0.4, TintColor = rgb(215, 225, 255) },
}

local NEON = {
	Lighting = { ClockTime = 22, Brightness = 0.5, Ambient = rgb(20, 10, 35), OutdoorAmbient = rgb(40, 20, 70),
		EnvironmentDiffuseScale = 0.4, EnvironmentSpecularScale = 1, ExposureCompensation = 0.2 },
	Atmosphere = { Density = 0.4, Offset = 0.05, Color = rgb(90, 40, 140), Decay = rgb(40, 10, 80), Glare = 0, Haze = 1.5 },
	BloomEffect = { Intensity = 1, Size = 40, Threshold = 0.9 },
	ColorCorrectionEffect = { Brightness = 0, Contrast = 0.15, Saturation = 0.25, TintColor = rgb(255, 235, 255) },
}

apply(DAY)
```

Recipe notes:

- **Day**: shadows do the work; keep `Ambient` dark so indoor areas read as indoor. Golden hour: `ClockTime = 17.5`,
  Atmosphere `Color = rgb(255, 200, 150)`, `Haze = 1`, `Glare = 0.5`.
- **Night**: never pure black. A blue `OutdoorAmbient` around 45-75 keeps the map readable; add warm `PointLight`s
  (`rgb(255, 190, 120)`, `Brightness` 1.5, `Range` 16) at lamps.
- **Horror**: darkness plus one strong light. Give the player a `SpotLight` flashlight (`Brightness` 3, `Range` 60,
  `Angle` 45, `Shadows = true`) on an attachment in the head or camera. Fog via Atmosphere `Density` and `Haze`.
- **Neon / cyberpunk**: `Enum.Material.Neon` signs, magenta `rgb(255, 0, 170)` and cyan `rgb(0, 220, 255)` lights
  (`Brightness` 2, `Range` 20, `Shadows = false`), high `EnvironmentSpecularScale` for wet-looking streets, bloom with
  a low threshold. Consider `LightingStyle = Soft` if you have many lights and need performance.
- **Interiors**: `SurfaceLight` on ceiling panels (`Face = Enum.NormalId.Bottom`, `Angle` 90 to 120, `Range` 18,
  `Brightness` 1.2, warm `rgb(255, 225, 190)`), lamps as `PointLight` with `Range` 10 to 14, `Ambient` around
  `rgb(55, 50, 45)` so corners aren't black, `ExposureCompensation` 0.2 to 0.4. One shadowed light per room at most.

Day/night cycle: change `ClockTime` on the server (for example `Lighting.ClockTime += dt * 24 / 600` per Heartbeat
for a 10-minute day) and swap recipes by tweening the numbers when it crosses sunrise or sunset.

## Mistakes to avoid

- Writing `Lighting.Technology` in scripts or recommending it. Use `LightingStyle` and `PrioritizeLightingQuality`.
- Bright `Ambient` with `EnvironmentDiffuseScale` at 1: everything looks flat and washed out.
- `OutdoorAmbient` lower than `Ambient` (it gets clamped up anyway) or both set to white.
- Bloom with `Threshold` near 0 and high `Intensity`: the whole screen glows.
- `Brightness` above 5 or `ExposureCompensation` far from 0 to fix a scene that really needs ambient changes.
- Hundreds of local lights, or many with `Shadows = true`.
- `Range` above 120 (it is clamped) or lights parented to Models or Folders (they don't shine).
- `Clouds` parented to Lighting (they only render under `workspace.Terrain`).
- `BlurEffect` or `DepthOfFieldEffect` left on during normal gameplay.
- Setting fog properties while an `Atmosphere` exists (they are ignored).