Lighting, rendering and compositing

SkillMedia

Guides your agent through lighting, rendering and compositing scenes in Blender.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the Lighting, rendering and compositing skill

About this skill

Use when lighting, rendering or compositing in Blender: light a character, product or hero shot, interior at dusk or night, three-point or motivated lighting, sun and sky, HDRI, EEVEE vs Cycles settings, light leaks or noise, flat or muddy renders, subject not standing out, AgX/ACES color management

What this skill tells your AI

The instructions your AI receives, as published by scenario-labs/skills in skills/dcc/blender/scenario-blender-lighting-rendering/SKILL.md and read by ahel’s review.

Expert lighting controls where the eye goes. Shape comes from gradients, the subject is separated from its surroundings by value (checked desaturated), every light has a source and a purpose, and every decision is measured on the render, not on lamp values. Work from a controlled base, change one thing at a time, and compare. If a sibling skill named here is missing from your available skills, ask the user to install it (npx skills add scenario-labs/skills --skill <name>); unattended, proceed from tool schemas and flag the gap.

REQUIRED BACKGROUND: scenario-blender-expert (execution channel, review loop, 5.2 API changes). Related: scenario-blender-texturing-shading (materials, skin SSS), scenario-blender-previs-storyboard (shot planning, cameras).

Toolkit: scripts/bx_light.py (tested on 5.2.1): rigs placed relative to subject and camera, EEVEE/Cycles presets, color setup and audit, 5.x compositor helpers, render analysis. Import: sys.path.append("<this skill>/scripts"); import bx_light as BL.

Stance (the expert delta)

  • Value separation first. Andy Goralczyk separates character from background by value in almost every shot and checks it desaturated. Andrew Price: the highest-contrast area becomes the focal point whether you want it or not (the bright window beats the couch). Fix by darkening the set before brightening the subject.
  • Light size and distance are the controls. Andrew: a large source reads form and hides pores, a small one reads texture and grit, so a face key is a large source, never a small bulb (unless toon or deliberately harsh). Inverse square is an attention tool: move a light closer instead of adding helpers. No key:fill ratio is a rule (Andrew: "half the key is bogus"): dim the shadow side until it reads as shadow with detail, and measure on the subject.
  • Motivate, then cheat plausibly. Every light needs a source and a color from the world (Gleb Alexandrov, Lino Thomas). Andy puts the rim on the key side, because on the shadow side it reads as a bounce from nowhere. When the source is behind the subject he fakes a key into the face. Shadow casters and light linking keep cheats off the set. Gleb stops before the image "looks lit".
  • EEVEE is a trench coat (Andrew). Ray tracing is off in a factory scene. World light passes through walls unless the volume probe's outer samples sit at the inner walls (Andrew; measured 0.26 leak to 0.002; 5.2.1 puts samples one spacing inside the box, so size the box from the points). Soft lights need per-light jitter (Gleb) and custom distance (measured: automatic distance loses 8 %).
  • Cycles economy (Andy, Sprite Fright): 3 bounces, no caustics, no clamping, Fast GI, and bounces faked with lights. Keep sharp speculars for the eyes and hero metal only.
  • Linear and wide until the end (Jacob Holiday). EXR stays linear while PNG bakes the view transform. AgX hides clipping (linear 4 displays 0.91), so read the EXR. Global brightness is exposure in the view transform, not scaled lights (keeps every ratio, including world and emissives). AgX for scenes, Khronos PBR Neutral for product color. Set the working space once (Nathan Vegdahl).
  • Rebalance in comp, not by re-rendering (Wyatt, Robin). In Cycles, light groups per role (key, fill, rim, window): one render, then gains in the compositor (BL.light_groups, BL.lightgroup_mix). EEVEE has no light-group outputs: use light linking and view layers.
  • Always comp, lightly (Pau Homs): bloom, vignette, then a correction, stopping before it reads as a filter. In 5.x the compositor is a node group.
  • Color has three contrasts (Lino): value, saturation and hue. Keep one saturated focus hue and desaturate its complement over large areas.

Establish first

InputWhy it changes the planDefault when silent
Still or animationContinuity, flicker and temporal denoiseStill
EngineEEVEE: stylized, fast iteration, volumes, NPR, viewport comp with passes. Cycles: glass close-ups, bounce realism, referenceEEVEE to iterate, plus a Cycles reference render
StyleToon terminators need a small, unjittered keyStylized-realistic
Subject and focus pointRig target (the face), mask for the analysisCharacter head, else bbox center
Time and motivationColor scheme: warm practicals, cool sky, sunNight/dusk interior: warm key (2,700 K [added]), cool fill
DeliveryPNG display plus EXR master; external grade?PNG + 32-bit multilayer EXR
Color fidelityBrand RGB: Khronos PBR Neutral; skin: ACES 2.0 or AgX High ContrastAgX
Late balance changes, comp hand-offCycles light groups per role, multilayer EXRgroups when rendering in Cycles

Workflow

  1. Compose, then lock the camera. Lighting is view dependent (Andrew). Use BL.screen_xy and BL.aim_camera_at_frame_point(head, 1/3 or 2/3, 0.62) for look room, and 80 mm for boxy products. GATE: one focal element; subject near a thirds point or a deliberate symmetry, pyramid or full frame.
  2. Controlled base. For a studio: world strength 0 and a near-black rough ground (Andrew). For an EEVEE interior: pb = BL.volume_probe_for_room(inner_lo, inner_hi, cell=0.5, wall=0.2) (outer samples on the inner walls), BL.probe_report(pb, inner_lo, inner_hi), then BL.bake_probes(). For an exterior: BL.outdoor_sun_sky(..., azimuth_space="world"). GATE: probe_report flags nothing and a world-only render of a sealed interior is near black.
  3. Key. Use BL.three_point, BL.motivated_interior (window + practical, cheated linked key, spot practical, rims, bounce) or BL.outdoor_sun_sky. Lights stay out of walls automatically. GATE: BL.light_report(target=head, face=head) has no flags (frontal key, key below the eye line, key smaller than the head), and a clay render (BL.clay(True)) gives internal_ratio >= 2.5.
  4. Supporting lights. Add fill, rim, bounce and BL.eye_light, plus BL.shadow_caster, BL.fake_sun, BL.split_world or BL.haze as needed. Linking lives on the light OBJECT (obj.light_linking, via BL.link_light), not the Light datablock. Adjust one lamp at a time: BL.light_contributions(lights, mask, dir), or in Cycles BL.lightgroup_check(exr, mask) from one render. GATE: the key has the largest share on the subject, the world is under 10 % indoors, and each rim is motivated.
  5. Measure and look. r = BL.render(base) gives PNG + EXR. Then mask = BL.mask_cryptomatte(r["exr"], names) (or BL.mask_workbench), rep = BL.analyse(r["png"], mask, exr=r["exr"]), BL.verdict(rep) and BL.value_study(...), and open the images. GATE: the verdict is empty and in the value study the subject owns a value group; otherwise darken the set, carve with spots or blockers, and link the key.
  6. Color. BL.color_setup(view, look, exposure) (brightness here, never by scaling lamps) and BL.color_audit(). GATE: the audit is empty, no complementary clash is flagged, clip is at most 0.5 % outside emitters, and the linear max is intended.
  7. Render settings. BL.preset_eevee(quality="final", interior=...) or BL.preset_cycles(quality="final", budget="film"). For EEVEE finals, render a Cycles preview reference (Andrew). GATE: the subject is within about 30 % of Cycles and there are no engine artifacts (critique section 7).
  8. Comp. Cycles: mix = BL.lightgroup_mix(gains, exr=r["exr"]) re-grades key/fill/rim/window from the EXR in about 0.2 s (BL.set_gain, RGB gains recolor). Then BL.comp_finish(bloom=0.25, vignette=0.3, contrast=0.05, source=mix["socket"]); masks with BL.matte(tree, names); pixel sizes through BL.relative_px; passes, back to beauty and view layers are in procedures P13. GATE: re-run the verdict on the finished frame; the vignette ratio should fall.
  9. Deliver with evidence: final PNG, EXR, value study, the light table, the verdict, and what was not verified.

Animation: pin the sun per location with sun_azimuth within about 30 deg (Andy). Light the wide shot and propagate it to coverage. Check shots with BL.contact_sheet and BL.sheet_stats (outliers more than 0.5 stop from the median). Keep temporal denoise on and never use ray-tracing resolution 1/16.

Numbers

ValueRelative toSource
Level of a white card: point P/(4π²d²), area P/(π²d²), sun S/πBL.energy_formeasured, both engines
Source as big as its distance delivers 75 % of the nominal levelapparent sizemeasured
AgX display: 0.18 to 0.463, 1.0 to 0.773, 4.0 to 0.910linear valuemeasured
Key 40 deg off axis, 35 deg up, 3 subject radii, size = radiussubject, camera[added] defaults
Frontal flag: key < 20 deg off the camera axiscamera axis[added]
Sun angle about 2 deg; continuity ±30 degsetAndy
Kelvin: candle 1,500, incandescent 2,000 to 2,500, daylight 6,500 (practical default 2,700 [added])lightAndrew
EEVEE: RT 1:1 and GI 1:2 for finals, Fast GI steps 16, shadow steps 12 to 16 (leaks), shadow rays 2 (penumbra)renderAndrew
Volume probe: outer samples on the inner walls (samples at local (i+1)/(N+1)x2-1); leak 0.22 at 0.44 m inside, 0.054 at 0.2 m, 0.002 at the wall, 0.009 past the wall; surfel density 100roomAndrew, measured
Brand color error (of 255): Khronos 3.8, AgX 27 to 42, Standard 33white furnacemeasured
Haze density about 0.05 for a roomvolumeAndrew
Cycles film: 3 bounces, clamp 0, no caustics, 100 test / 500 to 1,500 final samplesrenderAndy
EXR: multilayer, half float, DWAA for comp; 32-bit mastersoutputRobin, Andy
Verdict: surround separation ≥ 0.10, edge merge ≤ 35 %, clay form ratio ≥ 2.5, value range ≥ 0.30, clip ≤ 0.5 %display luma[added], calibrated

Quality gates

Measurable:

rep = BL.analyse(png, mask, exr=exr); problems = BL.verdict(rep)          # [] = pass
flags = BL.light_report(target=head, face=head)["flags"]; audit = BL.color_audit()
probe = BL.probe_report(pb, inner_lo, inner_hi)["flags"]                  # EEVEE interiors: []
groups = BL.lightgroup_check(exr, mask)                                   # Cycles: rel_error ~0, shares
shares = BL.light_contributions(lights, mask, out_dir)                   # per-light share on subject

Visual: open the render, the value_study panel (desaturated | value groups | squint) and, for sequences, the contact sheet. Judge them with references/critique.md: first read, value structure, form, motivation, color, composition, artifacts, finish.

Common mistakes

MistakeWhat it looks likeFix
Frontal keyFlat, "flash photo", clay form ratio about 1.3Key 30 to 60 deg off axis, above the eye line
Practical behind the subject used as the keyDull face, bright wall steals focusCheated key on the source's side, linked to the subject
Bare point practical near a wallBlown wall, shelf becomes the focal pointSpot with the shade's cone; blocker
EEVEE interior without probe, or a probe box drawn to the wallsShadows lifted blue/gray everywhere, muddyOuter samples at the inner walls (probe_report), bake, sealed-room test
Small bulb as a face keyPores and texture, harsh faceLarge source (head-sized or more); flag in light_report(face=)
Brightening by scaling lampsWorld and emissives left behind, ratios driftexposure in the view transform
light.data.light_linkingAttributeErrorLinking and light groups are Object properties
Re-rendering to rebalance lightsHours per tweakCycles light groups + lightgroup_mix
Rig lights inside wallsA rim that contributes nothingavoid=subject (default in rigs)
Unlinked faked keySet brightens with the subject, no separationlink_key=True; key share high, background share near 0
Judging clipping on AgX PNGHighlights look fine, EXR at 20+Read linear_max, use exposure
Big soft jittered key on a toon materialDithered, noisy terminatorSmall unjittered key for NPR (Wyatt: crisp shadows for toon)
Inverted hull outlineCharacter goes dark or flatOutline material transparent to shadow rays (outline_hull)
AOV named in shader onlyPass silently missingBL.register_aovs()
Pixel-sized comp effectsLook changes between preview and finalBL.relative_px
Exclude instead of indirect-only in layersMissing shadows in the compindirect_only (0.0004 vs 0.016 diff)

Blender 5.2 notes

  • EEVEE id is BLENDER_EEVEE; use_raytracing is False by default; use_bloom/ssr/gtao/soft_shadows are gone (Glare node, ray tracing, Fast GI, per-light jitter).
  • Probes are SPHERE/PLANE/VOLUME; lightprobe_cache_bake runs synchronously headless; the sphere-probe default is 512. Volume samples sit one spacing inside the box faces, never on them.
  • EEVEE writes Cryptomatte but no Object Index pass; light groups are Cycles only (EEVEE Render Layers has no Combined_<group>); light linking works in both engines. light_linking and lightgroup are Object properties; bpy.types.Light has neither.
  • Compositor: scene.compositing_node_group, Group Output, ShaderNodeMix (color sockets 6/7, result 2), menu inputs take display names ('Bloom'). GPU is the default device. Assets live in datafiles/assets/nodes/compositing_nodes_essentials.blend.
  • Color: the working space is read-only (use bpy.ops.wm.set_working_color_space); looks are prefixed ('AgX - Punchy'); 'Linear'/'Raw' are rejected; camera log spaces exist; Principled Thin Wall exists for window glass.
  • matrix_world is stale after setting a transform; call view_layer.update(). OIIO read_image(subimage, ...): the first argument selects the part.

References

  • references/procedures.md: tested code for every stage (P1 units to P17 exposure and color), with measured results and test paths. Load before writing code.
  • references/critique.md: the rubric to judge a render or sequence, in expert reading order, with the code check behind each question.
  • references/expert-notes.md: principles per expert with timestamps, plus the disagreements table. Load for judgment calls and attribution.
  • references/sources.md: the 15 videos, credentials, best timestamps, and which to consult for which question.

Signals

GitHub stars
681
Forks
82
Last commit
Sep 2026
Advanced
Item type
skill
Key
scenario-blender-lighting-rendering
Source
github.com/scenario-labs/skills