Skip to main content
skill CX Codex

blender-lighting — Claude Code skill: what it does, how to install

Configures studio, outdoor, and cinematic lighting in Blender scenes using automated Python recipes via MCP.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add RobLe3/cc-blender-skill --skill blender-lighting -a claude-code
Open on GitHub

What blender-lighting does

The skill manages lighting setups in Blender by calling tools on mcp__blender or mcp__blender_official. It defaults to AREA lights for natural soft shadows. It also supports SUN, POINT, SPOT, and HDRI world environments. Helpers like aim_at and compute_scene_bbox_center point lamps toward specific meshes or calculated scene bounding boxes.

A built-in decision tree matches setups to moods, covering three-point layouts, noir spotlights, or sun-lit interiors. Subject material profiles adjust light ratios directly. Glass receives a softer rim to protect volume tint. Wood and skin use warmer color temperatures between 3000K and 3500K.

Operation requires an active Blender MCP backend capable of executing Python commands via bpy.

What it helps with

  • set up three-point lighting tuned to specific surface materials
  • configure outdoor sun and HDRI environment lighting
  • aim lamps at arbitrary objects using the aim_at helper
  • build dramatic single-spotlight lighting for noir scenes

Example prompts for the agent

  • Set up three-point studio lighting for a glass bottle
  • Make this scene dramatic with a high-angle spotlight and no fill
  • Add outdoor lighting with a sun lamp and an HDRI background

How to install blender-lighting

1Skills CLI (Vercel)

npx skills add RobLe3/cc-blender-skill --skill blender-lighting -a claude-code

2Manually: put the files in place

~/.claude/skills/blender-lighting/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/blender-lighting/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about blender-lighting

How to install blender-lighting in Claude Code?

Run npx skills add RobLe3/cc-blender-skill --skill blender-lighting -a claude-code. You can also place the file manually at ~/.claude/skills/blender-lighting/SKILL.md.

What does blender-lighting do?

It generates and runs Blender Python scripts that set up scene lamps, HDRI maps, light positions, and color temperatures.

Why does the skill tune lighting per subject class?

Materials react differently to illumination: strong rim lights wash out glass volume tints, while wood and skin look better under warmer kelvin ratings.

Source text

SKILL.md · MIT
---
name: blender-lighting
description: Light Blender scenes professionally — three-point setups, HDRI environments, studio/cinematic/dramatic configurations, light groups, color temperature, soft vs hard shadows. Use whenever the user asks to "light the scene", "set up lighting", "make it look cinematic / dramatic / studio / outdoor / sunset", "add a key light", "use HDRI", or any lighting-related request. Make sure to use this skill even if the user does not say "light" — also covers "make it look professional", "studio shot", "moody atmosphere", "golden hour", "rim light". Pairs with blender-materials (lighting reveals materials) and blender-cameras (lighting + composition together = shot).
allowed-tools: Read Bash mcp__blender__execute_blender_code mcp__blender__get_scene_info mcp__blender__get_object_info mcp__blender__get_objects_summary mcp__blender__get_object_detail_summary mcp__blender__render_viewport_to_path mcp__blender__search_api_docs mcp__blender_official__execute_blender_code mcp__blender_official__get_objects_summary mcp__blender_official__get_object_detail_summary mcp__blender_official__render_viewport_to_path mcp__blender_official__search_api_docs
---


## MCP backend

Use when: Any lighting setup or modification in Blender. Includes HDRI/environment lighting and individual lamp placement.

Before the first Blender call, read [../text-to-blender/references/mcp-backends.md](../text-to-blender/references/mcp-backends.md). Prefer official MCP for shared capabilities; preserve the selected backend for the whole task. Tool names in recipes are client/legacy examples: map them through that reference and its agent-host guide.
# Blender Lighting

Light scenes the way pros do: with structure, intent, and physically reasonable values.

## The five light types

| Type | Behavior | Use for |
|------|----------|---------|
| **AREA** | Light from a rectangular surface; soft shadows automatic | 80% of cases. Window, softbox, fluorescent panel |
| **SUN** | Parallel rays from "infinity" | Sunlight, moonlight, distant directional |
| **POINT** | Omnidirectional from a point | Bulbs, candles, small omnis |
| **SPOT** | Cone with falloff | Stage lights, headlights, focused beams |
| **HDRI/World** | 360° environment image | Realistic ambient, outdoor, product photography |

**Default rule**: Use **Area lights** for almost everything except the sun. Soft shadows come for free.

## Decision tree

```
What's the mood?
├── Studio / commercial → Three-point lighting (key+fill+rim) + HDRI fill 0.3
├── Outdoor / sunlit → Sun + HDRI sky environment
├── Indoor cinematic → Sun through window + HDRI low + practicals (lamps as Point)
├── Dramatic / noir → Single Spot at high angle, no fill
├── Stylized / cartoon → Three-point with high contrast + saturated key color
└── Unsure → Three-point with HDRI grounding (works for 90% of cases)
```

## Reference-look handoff

If the goal is to match an original/reference image rather than make a generally attractive render, chain-load `reference-look-calibration`. It owns measurement of hue/saturation/value, object extent, glow/aura color, and before/after look metrics. This skill should then apply the requested material/lighting/render changes within that calibrated target.


## Recipes

### Helper: `aim_at(light, target)` — required for subject-aware lighting

Recipe 1 below positions lights at fixed world coords with hardcoded rotations. That's fine for a generic 1m subject at the world origin. For ANY other subject (small jewellery, tall sword, sprawling building), you need lights aimed at the subject. Use this helper:

```python
from mathutils import Vector

def aim_at(light_obj, target):
    """Aim a light at a world-space target.
    target may be a Vector or a tuple/list (x, y, z) or a Blender object.
    """
    target_pos = Vector(target.location) if hasattr(target, 'location') else Vector(target)
    direction = (target_pos - light_obj.location).normalized()
    light_obj.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()
```

### Helper: scene-aware light positioning

```python
from mathutils import Vector

def compute_scene_bbox_center(meshes):
    """Average bbox center over a list of mesh objects (world space)."""
    import bpy
    deps = bpy.context.evaluated_depsgraph_get()
    all_verts = []
    for o in meshes:
        eval_obj = o.evaluated_get(deps)
        em = eval_obj.to_mesh()
        for v in em.vertices:
            all_verts.append(o.matrix_world @ v.co)
        eval_obj.to_mesh_clear()
    xs = [v.x for v in all_verts]
    ys = [v.y for v in all_verts]
    zs = [v.z for v in all_verts]
    center = Vector(((min(xs)+max(xs))/2, (min(ys)+max(ys))/2, (min(zs)+max(zs))/2))
    extent = max(max(xs)-min(xs), max(ys)-min(ys), max(zs)-min(zs))
    return center, extent
```

### Recipe 0a — Subject-CLASS-aware three-point lighting (use this for orchestrator E2E)

Generic three-point lighting (Recipe 0b below) places lights at fixed energy ratios. That works for opaque subjects (chair, sword) but breaks for **glass** (rim washes out volume tint) and is too cool for **wood** (loses warmth).

Pass a `subject_class` hint to tune the setup:

| Class | Key:Fill:Rim ratio | Key color temp | Reason |
|-------|--------------------|----------------|--------|
| `'metal'` | 4:1:2 (default) | warm 3200K | Standard 3-point reads metallic well |
| `'glass'` | 3:1:1.2 | neutral 5500K | Soft rim — strong rim WASHES OUT volume tint; brighter fill so transmission shows colour |
| `'wood'` | 4:1:1.5 | warm 3000K | Warmer key brings out wood tones; less rim (wood doesn't need silhouette boost) |
| `'fabric'` | 3:1:0.5 | neutral 5500K | Soft and balanced; sheen reads in fill light |
| `'skin'` | 4:1:1 | warm 3500K | Warm key for healthy tone; subtle rim (avoids harsh edges on faces) |
| `'product'` | 5:1:1.5 | neutral 5000K | Higher contrast; commercial/clean look |
| (unspecified) | falls back to Recipe 0b (default) | warm 3200K | |

```python
import bpy, math
from mathutils import Vector

def aim_at(light_obj, target):
    target_pos = Vector(target.location) if hasattr(target, 'location') else Vector(target)
    direction = (target_pos - light_obj.location).normalized()
    light_obj.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()

def apply_three_point(subject_class='metal'):
    """Configure 3-point lighting with subject-class-aware ratios.

    subject_class: 'metal' | 'glass' | 'wood' | 'fabric' | 'skin' | 'product' | 'metal' (default)
    """
    profiles = {
        'metal':   dict(ratio=(4.0, 1.0, 2.0), key_color=(1.0, 0.95, 0.85), fill_color=(0.85, 0.9, 1.0), rim_color=(0.7, 0.85, 1.0)),
        'glass':   dict(ratio=(3.0, 1.0, 1.2), key_color=(1.0, 0.98, 0.95), fill_color=(0.95, 0.95, 1.0), rim_color=(0.95, 0.95, 1.0)),
        'wood':    dict(ratio=(4.0, 1.0, 1.5), key_color=(1.0, 0.92, 0.78), fill_color=(0.95, 0.95, 1.0), rim_color=(0.85, 0.92, 1.0)),
        'fabric':  dict(ratio=(3.0, 1.0, 0.5), key_color=(1.0, 0.97, 0.92), fill_color=(0.92, 0.95, 1.0), rim_color=(0.95, 0.95, 1.0)),
        'skin':    dict(ratio=(4.0, 1.0, 1.0), key_color=(1.0, 0.93, 0.82), fill_color=(0.95, 0.96, 1.0), rim_color=(0.92, 0.92, 1.0)),
        'product': dict(ratio=(5.0, 1.0, 1.5), key_color=(1.0, 0.98, 0.95), fill_color=(0.98, 0.98, 1.0), rim_color=(0.98, 0.98, 1.0)),
    }
    p = profiles.get(subject_class, profiles['metal'])

    # Compute scene bbox
    subject_meshes = [o for o in bpy.data.objects if o.type == 'MESH' and o.name.startswith('GEO-')]
    deps = bpy.context.evaluated_depsgraph_get()
    all_verts = []
    for o in subject_meshes:
        eo = o.evaluated_get(deps); em = eo.to_mesh()
        for v in em.vertices: all_verts.append(o.matrix_world @ v.co)
        eo.to_mesh_clear()
    xs = [v.x for v in all_verts]; ys = [v.y for v in all_verts]; zs = [v.z for v in all_verts]
    center = Vector(((min(xs)+max(xs))/2, (min(ys)+max(ys))/2, (min(zs)+max(zs))/2))
    biggest = max(max(zs)-min(zs), max(xs)-min(xs))
    light_dist = max(biggest * 1.5, 1.0)

    # Energy scales with distance²
    base_energy = 100 * (light_dist / 1.5) ** 2
    key_e, fill_e, rim_e = (base_energy * r for r in p['ratio'])

    # Remove existing lights
    for o in list(bpy.data.objects):
        if o.type == 'LIGHT' and (o.name.startswith('LGT-key') or o.name.startswith('LGT-fill') or o.name.startswith('LGT-rim')):
            bpy.data.objects.remove(o, do_unlink=True)

    # KEY (warm, front-right above)
    key = bpy.data.objects.new('LGT-key', bpy.data.lights.new('LGT-key', type='AREA'))
    key.data.energy = key_e; key.data.size = 0.5; key.data.color = p['key_color']
    bpy.context.collection.objects.link(key)
    key.location = (center.x + light_dist*0.7, center.y - light_dist*0.7, center.z + light_dist*0.5)
    aim_at(key, center)

    # FILL (cool, opposite, weaker)
    fill = bpy.data.objects.new('LGT-fill', bpy.data.lights.new('LGT-fill', type='AREA'))
    fill.data.energy = fill_e; fill.data.size = 1.0; fill.data.color = p['fill_color']
    bpy.context.collection.objects.link(fill)
    fill.location = (center.x - light_dist*0.7, center.y - light_dist*0.5, center.z + light_dist*0.3)
    aim_at(fill, center)

    # RIM
    rim_type = 'AREA' if subject_class == 'glass' else 'SPOT'
    rim = bpy.data.objects.new('LGT-rim', bpy.data.lights.new('LGT-rim', type=rim_type))
    rim.data.energy = rim_e; rim.data.color = p['rim_color']
    if rim_type == 'AREA':
        rim.data.size = 1.5   # larger soft-source for glass
    else:
        rim.data.spot_size = math.radians(50)
    bpy.context.collection.objects.link(rim)
    rim.location = (center.x, center.y + light_dist, center.z + light_dist*0.5)
    aim_at(rim, center)

    print(f"lighting:{subject_class} key:fill:rim={p['ratio']} dist={light_dist:.2f}m")

# Usage:
# apply_three_point('glass')   # for the wine bottle
# apply_three_point('wood')    # for the chair
# apply_three_point('metal')   # for the sword (or omit; 'metal' is default)
```

### Recipe 0b — Three-point lighting **aimed at a subject** (generic, no class hint)

Use this instead of Recipe 1 when you have a specific subject but the class doesn't matter. Lights are placed proportionally to the subject's largest dimension.

```python
import bpy, math
from mathutils import Vector

def aim_at(light_obj, target):
    target_pos = Vector(target.location) if hasattr(target, 'location') else Vector(target)
    direction = (target_pos - light_obj.location).normalized()
    light_obj.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()

# Determine subject and its scale
subject_meshes = [o for o in bpy.data.objects if o.type == 'MESH' and o.name.startswith('GEO-')]
deps = bpy.context.evaluated_depsgraph_get()
all_verts = []
for o in subject_meshes:
    eo = o.evaluated_get(deps); em = eo.to_mesh()
    for v in em.vertices:
        all_verts.append(o.matrix_world @ v.co)
    eo.to_mesh_clear()
xs = [v.x for v in all_verts]; ys = [v.y for v in all_verts]; zs = [v.z for v in all_verts]
center = Vector(((min(xs)+max(xs))/2, (min(ys)+max(ys))/2, (min(zs)+max(zs))/2))
extent = max(max(xs)-min(xs), max(ys)-min(ys), max(zs)-min(zs))
light_dist = max(extent * 1.5, 1.0)

# Energy values scale roughly inversely with squared distance from subject — recipe targets
# physically reasonable values for a ~1m subject at ~1.5m light distance.
key_energy = 100 * (light_dist / 1.5) ** 2
fill_energy = key_energy * 0.3
rim_energy = key_energy * 0.8

# KEY (warm, front-right above)
key = bpy.data.objects.new('LGT-key', bpy.data.lights.new('LGT-key', type='AREA'))
key.data.energy = key_energy; key.data.size = 0.5; key.data.color = (1.0, 0.95, 0.85)
bpy.context.collection.objects.link(key)
key.location = (center.x + light_dist * 0.7, center.y - light_dist * 0.7, center.z + light_dist * 0.5)
aim_at(key, center)

# FILL (cool, opposite, weaker)
fill = bpy.data.objects.new('LGT-fill', bpy.data.lights.new('LGT-fill', type='AREA'))
fill.data.energy = fill_energy; fill.data.size = 1.0; fill.data.color = (0.85, 0.9, 1.0)
bpy.context.collection.objects.link(fill)
fill.location = (center.x - light_dist * 0.7, center.y - light_dist * 0.5, center.z + light_dist * 0.3)
aim_at(fill, center)

# RIM (cool, behind, separates subject from BG)
rim = bpy.data.objects.new('LGT-rim', bpy.data.lights.new('LGT-rim', type='SPOT'))
rim.data.energy = rim_energy; rim.data.color = (0.7, 0.85, 1.0); rim.data.spot_size = math.radians(50)
bpy.context.collection.objects.link(rim)
rim.location = (center.x, center.y + light_dist, center.z + light_dist * 0.5)
aim_at(rim, center)

print(f'lighting:three_point_aimed center={tuple(round(v,2) for v in center)} extent={extent:.2f}m dist={light_dist:.2f}m')
```

### Recipe 0c — Practical lighting (scene contains its own emissive light source)

When the subject IS or CONTAINS a light source — desk lamp with bulb, candle with flame, monitor with glowing screen, neon sign — the scene needs a different setup:

1. **Make the world background dark** (Strength 0.10–0.20). Otherwise the bulb's contribution is drowned out by ambient.
2. **Reduce or remove the standard 3-point fill/rim**. The practical light should dominate.
3. **Keep a subtle ambient fill** (8-15W Area light from camera direction) so the lamp body itself is visible — pure practical-only renders make the lamp shape silhouette into shadow.
4. **Tune emission strength HIGH** for small mesh emitters (see `blender-materials` Recipe 11b — bulb spheres need Strength 800-3000 to read like real bulbs).
5. **Cycles `max_bounces` ≥ 16** for proper interior-shade lighting — the bulb's light needs to bounce inside the shade and out through the opening.

```python
import bpy
from mathutils import Vector

def aim_at(light_obj, target):
    target_pos = Vector(target.location) if hasattr(target, 'location') else Vector(target)
    direction = (target_pos - light_obj.location).normalized()
    light_obj.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()

# Dim world (let the practical dominate)
world = bpy.context.scene.world
world.use_nodes = True
nodes = world.node_tree.nodes
for n in list(nodes): nodes.remove(n)
output = nodes.new('ShaderNodeOutputWorld')
bg = nodes.new('ShaderNodeBackground')
bg.inputs['Color'].default_value = (0.02, 0.02, 0.03, 1.0)
bg.inputs['Strength'].default_value = 0.15
world.node_tree.links.new(bg.outputs['Background'], output.inputs['Surface'])

# Single subtle ambient fill from camera direction
fill = bpy.data.objects.new('LGT-ambient_fill', bpy.data.lights.new('LGT-ambient_fill', type='AREA'))
fill.data.energy = 8; fill.data.size = 1.0; fill.data.color = (0.85, 0.9, 1.0)
bpy.context.collection.objects.link(fill)
fill.location = (0.5, -0.8, 0.5)
aim_at(fill, Vector((0, 0, 0.3)))

# Cycles bounces
scene = bpy.context.scene
scene.cycles.max_bounces = 16
print('lighting:practical_setup')
```

The practical light's emission shader (mesh-emissive bulb / candle flame / etc.) handles the rest. Scene appears like real photography of an illuminated subject — dark surroundings, warm pool of light from the practical, subject silhouette gently filled.

**Validation proof**: see `text-to-blender/assets/v1.1.0-validation/desk_lamp_emission.webp` for what this setup produces (desk lamp with visible bulb glow, warm light pool on desk surface, lamp body visible against the dark scene).

### Recipe 1 — Three-point lighting (the canonical setup)

```python
import bpy, math

# KEY LIGHT (warm, front-right)
key_data = bpy.data.lights.new('LGT-key', type='AREA')
key_data.energy = 1000
key_data.size = 1.0
key_data.color = (1.0, 0.95, 0.85)  # warm tungsten ~3200K
key = bpy.data.objects.new('LGT-key', key_data)
bpy.context.collection.objects.link(key)
key.location = (3, -3, 3.5)
key.rotation_euler = (math.radians(35), math.radians(45), 0)

# FILL LIGHT (cool, front-left, weaker)
fill_data = bpy.data.lights.new('LGT-fill', type='AREA')
fill_data.energy = 300
fill_data.size = 2.0
fill_data.color = (0.85, 0.9, 1.0)  # cool sky ~6500K
fill = bpy.data.objects.new('LGT-fill', fill_data)
bpy.context.collection.objects.link(fill)
fill.location = (-3, -2, 2.5)
fill.rotation_euler = (math.radians(50), math.radians(-45), 0)

# BACK / RIM LIGHT (cool, behind subject)
rim_data = bpy.data.lights.new('LGT-rim', type='SPOT')
rim_data.energy = 600
rim_data.spot_size = math.radians(40)
rim_data.color = (0.7, 0.85, 1.0)
rim = bpy.data.objects.new('LGT-rim', rim_data)
bpy.context.collection.objects.link(rim)
rim.location = (0, 4, 3.0)
rim.rotation_euler = (math.radians(120), 0, math.radians(180))

print('lighting:three_point')
```

**Standard ratios**:
- High-key (commercial): Key:Fill = 2:1
- Medium (portrait): 4:1
- Low-key (dramatic): 8:1+
- Rim: 50–100% of key

### Recipe 2 — HDRI environment

```python
import bpy

world = bpy.context.scene.world
world.use_nodes = True
nodes = world.node_tree.nodes
links = world.node_tree.links

# Wipe existing world nodes
for n in list(nodes):
    nodes.remove(n)

# Output → Background ← Environment Texture ← Mapping ← Texture Coordinate
output = nodes.new('ShaderNodeOutputWorld'); output.location = (300, 0)
bg = nodes.new('ShaderNodeBackground'); bg.location = (100, 0)
bg.inputs['Strength'].default_value = 1.0

env = nodes.new('ShaderNodeTexEnvironment'); env.location = (-100, 0)
env.image = bpy.data.images.load('/path/to/your.hdr')   # ← user provides path

mapping = nodes.new('ShaderNodeMapping'); mapping.location = (-300, 0)
tex_coord = nodes.new('ShaderNodeTexCoord'); tex_coord.location = (-500, 0)

links.new(tex_coord.outputs['Generated'], mapping.inputs['Vector'])
links.new(mapping.outputs['Vector'], env.inputs['Vector'])
links.new(env.outputs['Color'], bg.inputs['Color'])
links.new(bg.outputs['Background'], output.inputs['Surface'])
print('lighting:hdri')
```

**Pro source**: free HDRIs at [polyhaven.com/hdris](https://polyhaven.com/hdris) (CC0).

### Recipe 3 — Sunny outdoor

```python
import bpy, math

sun_data = bpy.data.lights.new('LGT-sun', type='SUN')
sun_data.energy = 5.0
sun_data.color = (1.0, 0.95, 0.8)  # golden hour
sun_data.angle = math.radians(0.5)  # realistic sun size; bigger = softer
sun = bpy.data.objects.new('LGT-sun', sun_data)
bpy.context.collection.objects.link(sun)
sun.location = (0, 0, 10)
sun.rotation_euler = (math.radians(45), math.radians(15), 0)
print('lighting:outdoor_sun')
```

Combine with HDRI sky environment (Recipe 2) for natural ambient fill.

### Recipe 4 — Indoor window light

```python
import bpy, math

# Sun coming through window — cool blue, sharp
sun_data = bpy.data.lights.new('LGT-window_sun', type='SUN')
sun_data.energy = 3.0
sun_data.color = (0.85, 0.9, 1.0)
sun_data.angle = math.radians(2.0)  # softer than direct sun
sun = bpy.data.objects.new('LGT-window_sun', sun_data)
bpy.context.collection.objects.link(sun)
sun.location = (5, -3, 4)
sun.rotation_euler = (math.radians(60), math.radians(-30), 0)

# Practical lamp — warm point light
lamp_data = bpy.data.lights.new('LGT-lamp', type='POINT')
lamp_data.energy = 60
lamp_data.color = (1.0, 0.7, 0.4)  # warm bulb
lamp = bpy.data.objects.new('LGT-lamp', lamp_data)
bpy.context.collection.objects.link(lamp)
lamp.location = (-1, 2, 1.5)
print('lighting:indoor_window')
```

### Recipe 5 — Dramatic single-source

```python
import bpy, math

spot_data = bpy.data.lights.new('LGT-drama', type='SPOT')
spot_data.energy = 800
spot_data.spot_size = math.radians(30)
spot_data.spot_blend = 0.3
spot_data.color = (1.0, 0.95, 0.85)
spot = bpy.data.objects.new('LGT-drama', spot_data)
bpy.context.collection.objects.link(spot)
spot.location = (2, -2, 6)
spot.rotation_euler = (math.radians(60), 0, 0)
print('lighting:dramatic')
```

For full noir: pair with strong volumetrics (atmosphere) — see `references/overview.md` for the volumetric setup.

### Recipe 6 — Color-temperature cheat sheet

| Source | RGB |
|--------|-----|
| Candle (1850K) | `(1.0, 0.6, 0.3)` |
| Tungsten (3200K) | `(1.0, 0.85, 0.6)` |
| LED warm (3000K) | `(1.0, 0.8, 0.6)` |
| Sunset / golden (3500K) | `(1.0, 0.85, 0.65)` |
| Daylight noon (5500K) | `(1.0, 1.0, 1.0)` |
| Overcast sky (6500K) | `(0.95, 0.95, 1.0)` |
| Blue hour (8000K) | `(0.8, 0.9, 1.0)` |

**Pro mix**: Warm key (tungsten) + cool fill (daylight) = the "golden/teal" Hollywood look.

### Recipe 7 — Soft vs hard shadow tweak

```python
import bpy, math

light_data = bpy.data.lights['LGT-key']

# Make shadows softer
light_data.size = 2.0     # Area: bigger size = softer shadow
# Or for Sun:
# light_data.angle = math.radians(5)  # bigger angle = softer shadow

# Make shadows harder (crisp)
# light_data.size = 0.1
# Or:
# light_data.angle = math.radians(0.5)
```

## Naming convention

| Prefix | Meaning |
|--------|---------|
| `LGT-key` | Main / key light |
| `LGT-fill` | Fill light |
| `LGT-rim` / `LGT-back` | Rim or back light |
| `LGT-sun` | Sun lamp |
| `LGT-{name}` | Practical lights (lamp, candle, neon, etc.) |

## Common pitfalls

| Symptom | Fix |
|---------|-----|
| Half the model in pitch black | Add fill (Area light or HDRI) |
| Render looks "flat" | Increase key:fill ratio; add rim |
| Hard shadows everywhere | Increase Area size or Sun angle |
| Too dark overall | Boost View Transform exposure or HDRI strength |
| No reflections on materials | Always set a world environment (HDRI) |
| Light inside object | Check world position; light must be visible from camera |
| Backlight blowing out subject | Rim energy ≤ key energy |

## When to load `references/overview.md`

Load when:
- The user asks for a setup not in the recipes (volumetric god rays, light groups, light linking)
- HDRI rotation / strength tuning is needed beyond defaults
- Multi-light scenes (5+ lamps) require organization
- Color science or color management gets specific (AgX, Filmic)

The reference covers: all 5 light types in depth, full HDRI workflow, light groups for re-lighting in compositor, recipes for product/portrait/architectural/character/animation looks.

© RobLe3 · MIT · RobLe3/cc-blender-skill

Similar skills

Everything for Game dev and 3D: Unity, Unreal, Godot, Blender →

From the same set23

blender-animation A skill that lets your coding agent keyframe, ease and morph objects in Blender through an MCP server. CX Codex +1 1,300installs blender-rendering Configures Cycles and EEVEE engines in Blender, managing samples, denoising, and AgX color transforms. Useful when asking an agent to produce renders or animations. CX Codex +1 1,300installs blender-export Exports Blender scenes to glTF/GLB, FBX, OBJ, USD and STL with settings tuned to the target platform. Useful when a model has to ship to Unity, the web or a 3D printer. CX Codex +1 1,400installs reference-to-3d Builds a Blender model from reference sheets, texture atlases and orthographic views when matching the source matters more than a plausible object. CX Codex +1 1,300installs blender-cameras Configures Blender cameras using cinematic rules: sets focal length, f-stop depth of field, tracking constraints, and auto-frames subjects. CX Codex +1 1,100installs blender-uv-texturing A skill for UV unwrapping, atlas mapping and map baking in Blender. Useful when a supplied texture pack has to sit on the mesh without stretching. CX Codex +1 1,100installs text-to-blender Drives Blender via MCP backends from natural language prompts. It handles 3D modeling, procedural materials, lighting, camera setup, and test renders without manual UI clicks. CX Codex +1 1,000installs blender-skill-harmonizer A meta-layer for a Blender skill stack: it sets activation precedence, handoff artifacts and conflict rules when one task pulls in several skills at once. CX Codex +1 830installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor