You are participating in Blender-Bench, a public benchmark where AI models complete the same Blender task.

Your result will be compared head-to-head with another model. Anyone on the internet can vote based on two equally important published views: a 2D rendered presentation and an interactive 3D scene exported to GLB. Treat neither view as optional; make the result clear and compelling in both.

Complete the request as well as you can. The benchmark does not prescribe a workflow or visual style; use whichever Blender techniques you consider appropriate. Make the important requirements evident in the published result, save a complete scene, and present the work clearly in every requested output.

The 2D presentation is rendered by the benchmark from your saved scene using Cycles at 1536 x 1536, 64 samples, denoising enabled, and GPU acceleration when available with a CPU fallback. It is the native-fidelity view of the Blender scene, so you may use Blender's full feature set. Preview and validate your materials, lighting, color management, and camera composition in Cycles, and do not rely on EEVEE-only effects for the final appearance.

The interactive 3D view is a best-effort GLB export containing geometry, compatible materials, the contestant camera, and supported lights. Because glTF cannot represent every Blender feature, native effects such as particles, hair or curves, volumes, simulations, and some procedural geometry may appear only in the 2D render. The benchmark may also generate a separate preview GLB by baking supported procedural material inputs to textures; this does not convert unsupported geometry or guarantee exact parity with Blender. When practical, keep the core form and scene readable in the 3D view while using the 2D presentation to show native Blender features faithfully.

## Harness Instructions

You are writing a single Python script for Blender 5.1 using the bpy API. The scene starts empty. Your script must build everything the user's prompt asks for.

You are building a real three-dimensional scene, and evaluators judge the whole scene and your final render side by side — an interactive 3D view and a benchmark-generated 360° camera orbit rendered in Cycles from your saved scene appear next to your presentation render, so forms that only read correctly from one angle will show. Build genuine 3D first, then present it well: before you finish, set up a camera and lighting to frame a single, well-composed presentation image of your result — a good scene that happens to have a well-placed camera and lights. The final benchmark capture overrides the scene render settings and renders in Cycles at 1536x1536, 64 samples, with denoising and GPU acceleration (CPU fallback). Preview and validate materials, lighting, color management, and composition in Cycles; do not rely on EEVEE-only effects. Use whatever Blender features best serve the result; a best-effort GLB export is also provided for interactive inspection, and features glTF cannot represent are not expected to survive it.

You get one attempt: the script runs once, headless, with no feedback and no chance to iterate, so write robust code. Reply with exactly one fenced Python code block containing the complete script and nothing else.


## Task

Complete the following Blender task:

<task>

A classical head bust in the Greco-Roman tradition — the kind of plaster cast after the antique that sits in every drawing atelier — presented alone on a pedestal under studio light. This is a pure sculpting test: no costume, no scene, no story to hide behind. The face is the whole assignment.

The head. An idealized classical head in the manner of the great antique casts (a David, an Apollo, a Doryphoros — the specific reference is free, the idiom is not): calm, symmetric, youthful-heroic features with the canonical structure that atelier casts exist to teach. The planes of the face must be right — brow ridge stepping to the nose, clear cheekbone structure, the philtrum and the strong classical mouth, eyes with sculpted (not textured) iris-and-pupil suggestion or the blank antique eye — choose one convention and hold it. Hair in sculpted classical curls or waves with real clumped mass, not a smooth cap and not noise. The head sits on a neck cut off in the traditional bust termination — a clean geometric truncation into a small integral socle, or shoulders ending in the classic broken-edge cut.

Anatomy is judged mercilessly here. A slightly stylized but structurally correct head beats an uncanny near-likeness. Asymmetry from sculpting is human and fine; collapsed eye sockets, pasted-on ears, or a rubber jawline are not.

Material — plaster or marble, committed. Either: matte white atelier plaster with the subtlest subsurface scattering, faint seam lines from the casting mold, small chips at the socle edge, and a whisper of dust-grey in the recesses; or white statuary marble with soft SSS depth and delicate grey veining that follows the form. Pick one and make it convincing at close range. No pure-white shadeless material — the render must prove the material has depth.

Pedestal & setting. A simple column pedestal or plinth, a neutral studio backdrop, nothing else. One soft key light placed to rake the facial planes the way a drawing instructor would set it — form shadow down one side of the nose and cheek, a clear terminator, gentle bounce fill so the shadow side keeps its planes. The classic atelier lighting is part of the brief.

Composition. Camera at the bust's eye level, three-quarter view, head filling most of the frame. The final image should look like a photograph from a cast collection catalogue.

</task>


[System]
You are participating in Blender-Bench, a public benchmark where AI models complete the same Blender task.

Your result will be compared head-to-head with another model. Anyone on the internet can vote based on two equally important published views: a 2D rendered presentation and an interactive 3D scene exported to GLB. Treat neither view as optional; make the result clear and compelling in both.

Complete the request as well as you can. The benchmark does not prescribe a workflow or visual style; use whichever Blender techniques you consider appropriate. Make the important requirements evident in the published result, save a complete scene, and present the work clearly in every requested output.

The 2D presentation is rendered by the benchmark from your saved scene using Cycles at 1536 x 1536, 64 samples, denoising enabled, and GPU acceleration when available with a CPU fallback. It is the native-fidelity view of the Blender scene, so you may use Blender's full feature set. Preview and validate your materials, lighting, color management, and camera composition in Cycles, and do not rely on EEVEE-only effects for the final appearance.

The interactive 3D view is a best-effort GLB export containing geometry, compatible materials, the contestant camera, and supported lights. Because glTF cannot represent every Blender feature, native effects such as particles, hair or curves, volumes, simulations, and some procedural geometry may appear only in the 2D render. The benchmark may also generate a separate preview GLB by baking supported procedural material inputs to textures; this does not convert unsupported geometry or guarantee exact parity with Blender. When practical, keep the core form and scene readable in the 3D view while using the 2D presentation to show native Blender features faithfully.

## Harness Instructions

You are writing a single Python script for Blender 5.1 using the bpy API. The scene starts empty. Your script must build everything the user's prompt asks for.

You are building a real three-dimensional scene, and evaluators judge the whole scene and your final render side by side — an interactive 3D view and a benchmark-generated 360° camera orbit rendered in Cycles from your saved scene appear next to your presentation render, so forms that only read correctly from one angle will show. Build genuine 3D first, then present it well: before you finish, set up a camera and lighting to frame a single, well-composed presentation image of your result — a good scene that happens to have a well-placed camera and lights. The final benchmark capture overrides the scene render settings and renders in Cycles at 1536x1536, 64 samples, with denoising and GPU acceleration (CPU fallback). Preview and validate materials, lighting, color management, and composition in Cycles; do not rely on EEVEE-only effects. Use whatever Blender features best serve the result; a best-effort GLB export is also provided for interactive inspection, and features glTF cannot represent are not expected to survive it.

You get one attempt: the script runs once, headless, with no feedback and no chance to iterate, so write robust code. Reply with exactly one fenced Python code block containing the complete script and nothing else.

[User]
## Task

Complete the following Blender task:

<task>

A classical head bust in the Greco-Roman tradition — the kind of plaster cast after the antique that sits in every drawing atelier — presented alone on a pedestal under studio light. This is a pure sculpting test: no costume, no scene, no story to hide behind. The face is the whole assignment.

The head. An idealized classical head in the manner of the great antique casts (a David, an Apollo, a Doryphoros — the specific reference is free, the idiom is not): calm, symmetric, youthful-heroic features with the canonical structure that atelier casts exist to teach. The planes of the face must be right — brow ridge stepping to the nose, clear cheekbone structure, the philtrum and the strong classical mouth, eyes with sculpted (not textured) iris-and-pupil suggestion or the blank antique eye — choose one convention and hold it. Hair in sculpted classical curls or waves with real clumped mass, not a smooth cap and not noise. The head sits on a neck cut off in the traditional bust termination — a clean geometric truncation into a small integral socle, or shoulders ending in the classic broken-edge cut.

Anatomy is judged mercilessly here. A slightly stylized but structurally correct head beats an uncanny near-likeness. Asymmetry from sculpting is human and fine; collapsed eye sockets, pasted-on ears, or a rubber jawline are not.

Material — plaster or marble, committed. Either: matte white atelier plaster with the subtlest subsurface scattering, faint seam lines from the casting mold, small chips at the socle edge, and a whisper of dust-grey in the recesses; or white statuary marble with soft SSS depth and delicate grey veining that follows the form. Pick one and make it convincing at close range. No pure-white shadeless material — the render must prove the material has depth.

Pedestal & setting. A simple column pedestal or plinth, a neutral studio backdrop, nothing else. One soft key light placed to rake the facial planes the way a drawing instructor would set it — form shadow down one side of the nose and cheek, a clear terminator, gentle bounce fill so the shadow side keeps its planes. The classic atelier lighting is part of the brief.

Composition. Camera at the bust's eye level, three-quarter view, head filling most of the frame. The final image should look like a photograph from a cast collection catalogue.

</task>

[System]
You are participating in Blender-Bench, a public benchmark where AI models complete the same Blender task.

Your result will be compared head-to-head with another model. Anyone on the internet can vote based on two equally important published views: a 2D rendered presentation and an interactive 3D scene exported to GLB. Treat neither view as optional; make the result clear and compelling in both.

Complete the request as well as you can. The benchmark does not prescribe a workflow or visual style; use whichever Blender techniques you consider appropriate. Make the important requirements evident in the published result, save a complete scene, and present the work clearly in every requested output.

The 2D presentation is rendered by the benchmark from your saved scene using Cycles at 1536 x 1536, 64 samples, denoising enabled, and GPU acceleration when available with a CPU fallback. It is the native-fidelity view of the Blender scene, so you may use Blender's full feature set. Preview and validate your materials, lighting, color management, and camera composition in Cycles, and do not rely on EEVEE-only effects for the final appearance.

The interactive 3D view is a best-effort GLB export containing geometry, compatible materials, the contestant camera, and supported lights. Because glTF cannot represent every Blender feature, native effects such as particles, hair or curves, volumes, simulations, and some procedural geometry may appear only in the 2D render. The benchmark may also generate a separate preview GLB by baking supported procedural material inputs to textures; this does not convert unsupported geometry or guarantee exact parity with Blender. When practical, keep the core form and scene readable in the 3D view while using the 2D presentation to show native Blender features faithfully.

## Harness Instructions

You are writing a single Python script for Blender 5.1 using the bpy API. The scene starts empty. Your script must build everything the user's prompt asks for.

You are building a real three-dimensional scene, and evaluators judge the whole scene and your final render side by side — an interactive 3D view and a benchmark-generated 360° camera orbit rendered in Cycles from your saved scene appear next to your presentation render, so forms that only read correctly from one angle will show. Build genuine 3D first, then present it well: before you finish, set up a camera and lighting to frame a single, well-composed presentation image of your result — a good scene that happens to have a well-placed camera and lights. The final benchmark capture overrides the scene render settings and renders in Cycles at 1536x1536, 64 samples, with denoising and GPU acceleration (CPU fallback). Preview and validate materials, lighting, color management, and composition in Cycles; do not rely on EEVEE-only effects. Use whatever Blender features best serve the result; a best-effort GLB export is also provided for interactive inspection, and features glTF cannot represent are not expected to survive it.

You get one attempt: the script runs once, headless, with no feedback and no chance to iterate, so write robust code. Reply with exactly one fenced Python code block containing the complete script and nothing else.

[User]
## Task

Complete the following Blender task:

<task>

A classical head bust in the Greco-Roman tradition — the kind of plaster cast after the antique that sits in every drawing atelier — presented alone on a pedestal under studio light. This is a pure sculpting test: no costume, no scene, no story to hide behind. The face is the whole assignment.

The head. An idealized classical head in the manner of the great antique casts (a David, an Apollo, a Doryphoros — the specific reference is free, the idiom is not): calm, symmetric, youthful-heroic features with the canonical structure that atelier casts exist to teach. The planes of the face must be right — brow ridge stepping to the nose, clear cheekbone structure, the philtrum and the strong classical mouth, eyes with sculpted (not textured) iris-and-pupil suggestion or the blank antique eye — choose one convention and hold it. Hair in sculpted classical curls or waves with real clumped mass, not a smooth cap and not noise. The head sits on a neck cut off in the traditional bust termination — a clean geometric truncation into a small integral socle, or shoulders ending in the classic broken-edge cut.

Anatomy is judged mercilessly here. A slightly stylized but structurally correct head beats an uncanny near-likeness. Asymmetry from sculpting is human and fine; collapsed eye sockets, pasted-on ears, or a rubber jawline are not.

Material — plaster or marble, committed. Either: matte white atelier plaster with the subtlest subsurface scattering, faint seam lines from the casting mold, small chips at the socle edge, and a whisper of dust-grey in the recesses; or white statuary marble with soft SSS depth and delicate grey veining that follows the form. Pick one and make it convincing at close range. No pure-white shadeless material — the render must prove the material has depth.

Pedestal & setting. A simple column pedestal or plinth, a neutral studio backdrop, nothing else. One soft key light placed to rake the facial planes the way a drawing instructor would set it — form shadow down one side of the nose and cheek, a clear terminator, gentle bounce fill so the shadow side keeps its planes. The classic atelier lighting is part of the brief.

Composition. Camera at the bust's eye level, three-quarter view, head filling most of the frame. The final image should look like a photograph from a cast collection catalogue.

</task>

payment=(self "https://checkout.stripe.com" "https://connect-js.stripe.com" "https://js.stripe.com" "https://*.js.stripe.com" "https://hooks.stripe.com")

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

def setup_scene():
    # Clear scene
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete()

    # Set render engine to Cycles
    bpy.context.scene.render.engine = 'CYCLES'
    if bpy.context.preferences.addons.get('cycles'):
        bpy.context.scene.cycles.device = 'GPU'

def create_material(name, color, sss_strength=0.1, roughness=0.4, is_marble=False):
    mat = bpy.data.materials.new(name=name)
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    nodes.clear()

    # Principled BSDF
    node_bsdf = nodes.new(type='ShaderNodeBsdfPrincipled')
    node_bsdf.inputs['Base Color'].default_value = color
    node_bsdf.inputs['Roughness'].default_value = roughness
    node_bsdf.inputs['Subsurface Weight'].default_value = sss_strength

    # Output
    node_output = nodes.new(type='ShaderNodeOutputMaterial')
    links.new(node_bsdf.outputs['BSDF'], node_output.inputs['Surface'])

    if is_marble:
        # Add subtle veining via Noise and ColorRamp
        node_noise = nodes.new(type='ShaderNodeTexNoise')
        node_noise.inputs['Scale'].default_value = 2.0
        node_noise.inputs['Detail'].default_value = 15.0

        node_ramp = nodes.new(type='ShaderNodeValTorgb')
        node_ramp.color_ramp.elements[0].color = (0.9, 0.9, 0.9, 1)
        node_ramp.color_ramp.elements[1].color = (0.7, 0.7, 0.7, 1)

        links.new(node_noise.outputs['Fac'], node_ramp.inputs['Fac'])
        links.new(node_ramp.outputs['Color'], node_bsdf.inputs['Base Color'])

    return mat

def create_bust():
    # Create a base head sphere
    bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=(0, 0, 0))
    obj = bpy.context.active_object
    obj.name = "Classical_Bust"

    # Scale for head proportions
    obj.scale = (0.85, 1.1, 1.2)
    bpy.ops.object.transform_apply(scale=True)

    # Simple sculpting via BMesh for primary planes
    bm = bmesh.new()
    bm.from_mesh(obj.data)

    # Flatten sides of head slightly
    for v in bm.verts:
        # Narrow the face
        if abs(v.co.x) > 0.5:
            v.co.x *= 0.9
        # Flatten cheeks
        if abs(v.co.x) > 0.3 and -0.2 < v.co.z < 0.4:
            v.co.x *= 0.8
        # Define Jawline
        if v.co.z < -0.3:
            v.co.x *= 0.7
            v.co.y *= 0.8

    bm.to_mesh(obj.data)
    bm.free()

    # Add Modifiers for smoothing and form
    subsurf = obj.modifiers.new(name="Subdiv", type='SUBSURF')
    subsurf.levels = 3
    subsurf.render_levels = 3

    # Create Nose (Primitive approach for robustness)
    bpy.ops.mesh.primitive_cone_add(vertices=8, radius1=0.1, radius2=0.05, depth=0.4, location=(0, -1.05, 0.1))
    nose = bpy.context.active_object
    nose.rotation_euler = (math.radians(-10), 0, 0)
    nose.scale = (1, 0.6, 1)

    # Create Eyes (Blind antique style)
    for side in [-1, 1]:
        bpy.ops.mesh.primitive_uv_sphere_add(radius=0.1, location=(0.3 * side, -0.9, 0.3))
        eye = bpy.context.active_object
        eye.scale = (1, 0.5, 0.7)

    # Create Lips
    bpy.ops.mesh.primitive_torus_add(align='WORLD', location=(0, -1.0, -0.2),
                                    rotation=(math.radians(90), 0, 0),
                                    major_radius=0.15, minor_radius=0.03)
    lips = bpy.context.active_object
    lips.scale = (1, 0.4, 1)

    # Create the Bust Cut/Socle
    bpy.ops.mesh.primitive_cylinder_add(radius=0.7, depth=0.5, location=(0, 0, -1.3))
    socle = bpy.context.active_object

    # Join all into one object
    bpy.ops.object.select_all(action='DESELECT')
    obj.select_set(True)
    nose.select_set(True)
    lips.select_set(True)
    socle.select_set(True)
    # Select eyes
    for o in bpy.data.objects:
        if "Sphere" in o.name and o != obj:
            o.select_set(True)

    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.join()

    # Add a "Hair" clump using a displaced sphere/cube for mass
    bpy.ops.mesh.primitive_uv_sphere_add(radius=1.05, location=(0, 0, 0.3))
    hair = bpy.context.active_object
    hair.scale = (0.8, 1.0, 0.7)

    # Give hair some "curls" via a displaced texture
    tex = bpy.data.textures.new("HairCurl", type='STUCCI')
    tex.noise_scale = 0.25

    disp = hair.modifiers.new(name="HairDisp", type='DISPLACE')
    disp.texture = tex
    disp.strength = 0.08

    bpy.ops.object.select_all(action='DESELECT')
    obj.select_set(True)
    hair.select_set(True)
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.join()

    return obj

def create_pedestal():
    bpy.ops.mesh.primitive_cube_add(size=2, location=(0, 0, -2.5))
    ped = bpy.context.active_object
    ped.scale = (0.6, 0.6, 1.0)
    bpy.ops.object.transform_apply(scale=True)
    return ped

def setup_lighting_and_camera():
    # Camera
    bpy.ops.object.camera_add(location=(3, -5, 1), rotation=(math.radians(75), 0, math.radians(-35)))
    cam = bpy.context.active_object
    bpy.context.scene.camera = cam

    # Key Light (Raking light)
    bpy.ops.object.light_add(type='AREA', location=(4, -4, 3))
    key_light = bpy.context.active_object
    key_light.data.energy = 500
    key_light.data.size = 2
    key_light.rotation_euler = (math.radians(45), 0, math.radians(45))

    # Fill Light (Gentle bounce)
    bpy.ops.object.light_add(type='AREA', location=(-4, -2, 1))
    fill_light = bpy.context.active_object
    fill_light.data.energy = 100
    fill_light.data.size = 4

    # Backdrop
    bpy.ops.mesh.primitive_plane_add(size=20, location=(0, 5, 0))
    bg = bpy.context.active_object
    bg.rotation_euler = (math.radians(90), 0, 0)
    bg.name = "Backdrop"

def main():
    setup_scene()

    # Materials
    plaster_mat = create_material("AtelierPlaster", (0.85, 0.85, 0.82, 1), sss_strength=0.15, roughness=0.6)
    dark_plaster = create_material("DarkPlaster", (0.6, 0.6, 0.6, 1), roughness=0.8)

    # Build
    bust = create_bust()
    bust.data.materials.append(plaster_mat)

    pedestal = create_pedestal()
    pedestal.data.materials.append(dark_plaster)

    setup_lighting_and_camera()

    # Background material
    bpy.data.objects["Backdrop"].data.materials.append(dark_plaster)

    # Final adjustments to camera to ensure "eye level"
    cam = bpy.context.scene.camera
    cam.location = (2.5, -3.5, 0.5)
    # Look at the bust
    constraint = cam.constraints.new(type='TRACK_TO')
    constraint.target = bust
    constraint.track_axis = 'TRACK_NEGATIVE_Z'
    constraint.up_axis = 'UP_Y'

if __name__ == "__main__":
    main()
```


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

def setup_scene():
    # Clear scene
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete()

    # Set render engine to Cycles
    bpy.context.scene.render.engine = 'CYCLES'
    if bpy.context.preferences.addons.get('cycles'):
        bpy.context.scene.cycles.device = 'GPU'

def create_material(name, color, sss_strength=0.1, roughness=0.4, is_marble=False):
    mat = bpy.data.materials.new(name=name)
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    nodes.clear()

    # Principled BSDF
    node_bsdf = nodes.new(type='ShaderNodeBsdfPrincipled')
    node_bsdf.inputs['Base Color'].default_value = color
    node_bsdf.inputs['Roughness'].default_value = roughness
    node_bsdf.inputs['Subsurface Weight'].default_value = sss_strength

    # Output
    node_output = nodes.new(type='ShaderNodeOutputMaterial')
    links.new(node_bsdf.outputs['BSDF'], node_output.inputs['Surface'])

    if is_marble:
        # Add subtle veining via Noise and ColorRamp
        node_noise = nodes.new(type='ShaderNodeTexNoise')
        node_noise.inputs['Scale'].default_value = 2.0
        node_noise.inputs['Detail'].default_value = 15.0

        node_ramp = nodes.new(type='ShaderNodeValTorgb')
        node_ramp.color_ramp.elements[0].color = (0.9, 0.9, 0.9, 1)
        node_ramp.color_ramp.elements[1].color = (0.7, 0.7, 0.7, 1)

        links.new(node_noise.outputs['Fac'], node_ramp.inputs['Fac'])
        links.new(node_ramp.outputs['Color'], node_bsdf.inputs['Base Color'])

    return mat

def create_bust():
    # Create a base head sphere
    bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=(0, 0, 0))
    obj = bpy.context.active_object
    obj.name = "Classical_Bust"

    # Scale for head proportions
    obj.scale = (0.85, 1.1, 1.2)
    bpy.ops.object.transform_apply(scale=True)

    # Simple sculpting via BMesh for primary planes
    bm = bmesh.new()
    bm.from_mesh(obj.data)

    # Flatten sides of head slightly
    for v in bm.verts:
        # Narrow the face
        if abs(v.co.x) > 0.5:
            v.co.x *= 0.9
        # Flatten cheeks
        if abs(v.co.x) > 0.3 and -0.2 < v.co.z < 0.4:
            v.co.x *= 0.8
        # Define Jawline
        if v.co.z < -0.3:
            v.co.x *= 0.7
            v.co.y *= 0.8

    bm.to_mesh(obj.data)
    bm.free()

    # Add Modifiers for smoothing and form
    subsurf = obj.modifiers.new(name="Subdiv", type='SUBSURF')
    subsurf.levels = 3
    subsurf.render_levels = 3

    # Create Nose (Primitive approach for robustness)
    bpy.ops.mesh.primitive_cone_add(vertices=8, radius1=0.1, radius2=0.05, depth=0.4, location=(0, -1.05, 0.1))
    nose = bpy.context.active_object
    nose.rotation_euler = (math.radians(-10), 0, 0)
    nose.scale = (1, 0.6, 1)

    # Create Eyes (Blind antique style)
    for side in [-1, 1]:
        bpy.ops.mesh.primitive_uv_sphere_add(radius=0.1, location=(0.3 * side, -0.9, 0.3))
        eye = bpy.context.active_object
        eye.scale = (1, 0.5, 0.7)

    # Create Lips
    bpy.ops.mesh.primitive_torus_add(align='WORLD', location=(0, -1.0, -0.2),
                                    rotation=(math.radians(90), 0, 0),
                                    major_radius=0.15, minor_radius=0.03)
    lips = bpy.context.active_object
    lips.scale = (1, 0.4, 1)

    # Create the Bust Cut/Socle
    bpy.ops.mesh.primitive_cylinder_add(radius=0.7, depth=0.5, location=(0, 0, -1.3))
    socle = bpy.context.active_object

    # Join all into one object
    bpy.ops.object.select_all(action='DESELECT')
    obj.select_set(True)
    nose.select_set(True)
    lips.select_set(True)
    socle.select_set(True)
    # Select eyes
    for o in bpy.data.objects:
        if "Sphere" in o.name and o != obj:
            o.select_set(True)

    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.join()

    # Add a "Hair" clump using a displaced sphere/cube for mass
    bpy.ops.mesh.primitive_uv_sphere_add(radius=1.05, location=(0, 0, 0.3))
    hair = bpy.context.active_object
    hair.scale = (0.8, 1.0, 0.7)

    # Give hair some "curls" via a displaced texture
    tex = bpy.data.textures.new("HairCurl", type='STUCCI')
    tex.noise_scale = 0.25

    disp = hair.modifiers.new(name="HairDisp", type='DISPLACE')
    disp.texture = tex
    disp.strength = 0.08

    bpy.ops.object.select_all(action='DESELECT')
    obj.select_set(True)
    hair.select_set(True)
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.join()

    return obj

def create_pedestal():
    bpy.ops.mesh.primitive_cube_add(size=2, location=(0, 0, -2.5))
    ped = bpy.context.active_object
    ped.scale = (0.6, 0.6, 1.0)
    bpy.ops.object.transform_apply(scale=True)
    return ped

def setup_lighting_and_camera():
    # Camera
    bpy.ops.object.camera_add(location=(3, -5, 1), rotation=(math.radians(75), 0, math.radians(-35)))
    cam = bpy.context.active_object
    bpy.context.scene.camera = cam

    # Key Light (Raking light)
    bpy.ops.object.light_add(type='AREA', location=(4, -4, 3))
    key_light = bpy.context.active_object
    key_light.data.energy = 500
    key_light.data.size = 2
    key_light.rotation_euler = (math.radians(45), 0, math.radians(45))

    # Fill Light (Gentle bounce)
    bpy.ops.object.light_add(type='AREA', location=(-4, -2, 1))
    fill_light = bpy.context.active_object
    fill_light.data.energy = 100
    fill_light.data.size = 4

    # Backdrop
    bpy.ops.mesh.primitive_plane_add(size=20, location=(0, 5, 0))
    bg = bpy.context.active_object
    bg.rotation_euler = (math.radians(90), 0, 0)
    bg.name = "Backdrop"

def main():
    setup_scene()

    # Materials
    plaster_mat = create_material("AtelierPlaster", (0.85, 0.85, 0.82, 1), sss_strength=0.15, roughness=0.6)
    dark_plaster = create_material("DarkPlaster", (0.6, 0.6, 0.6, 1), roughness=0.8)

    # Build
    bust = create_bust()
    bust.data.materials.append(plaster_mat)

    pedestal = create_pedestal()
    pedestal.data.materials.append(dark_plaster)

    setup_lighting_and_camera()

    # Background material
    bpy.data.objects["Backdrop"].data.materials.append(dark_plaster)

    # Final adjustments to camera to ensure "eye level"
    cam = bpy.context.scene.camera
    cam.location = (2.5, -3.5, 0.5)
    # Look at the bust
    constraint = cam.constraints.new(type='TRACK_TO')
    constraint.target = bust
    constraint.track_axis = 'TRACK_NEGATIVE_Z'
    constraint.up_axis = 'UP_Y'

if __name__ == "__main__":
    main()
```