Install
openclaw skills install @vargai/blender-code-filmMake a short 3D film in Blender written entirely in Python by an agent (Claude Fable 5.2, Claude Code, Codex): the shots and the look as data, a world built from code (procedural terrain, hundreds of instanced props, node materials, lights, haze), one camera per shot bound to timeline markers, a stills-first approval pass, a quarter-size draft, a contact-sheet audit, a fresh critic subagent, then the final render to PNG frames and an ffmpeg encode with an optional varg music bed. Includes a tested starter (scripts/film.py, a 9 s three-shot film) and the Blender 5.x traps that turn frames black. Use when someone asks for a Blender animation or film made with code or Python, "make a video in Blender with Claude", a 3D short, music video, toy commercial or product film rendered in Blender, a low-poly or storybook 3D film, or a remake of a viral Fable 5.2 Blender video. Not for previz that feeds Seedance (code-to-video-previz, varg-previz), three.js films in the browser (karpathy-3d-story, code-3d-explainer), recording a browser game (code-game-trailer), 2D motion graphics (hyperframes, kinetic-type-art) or AI-generated footage (varg-ai).
openclaw skills install @vargai/blender-code-filmAn agent can make a finished 3D film without touching Blender's interface: it writes one Python file that builds the world, places the cameras and renders the frames. On the day Claude Fable 5.2 came out (2026-11-09) this was one of the most saved formats on X:
The starter in scripts/film.py is this skill's own test: a lantern orb drifts up a low-poly forest valley
at dusk in three shots (wide, follow, reveal), with haze, sparks and a warm rim light. Nothing is downloaded.
Put these to the person (in their language) and wait:
estimate_cost), or sounds
synthesized in code.blender --version || brew install --cask blender # or the installer from blender.org
blender -b --factory-startup -P scripts/film.py -- --stills --draft --out render/stills
Always run headless (-b) with --factory-startup so the user's add-ons and preferences can't change the
picture. Arguments after -- go to the script.
Everything that changes the picture sits at the top of film.py:
LOOK: the palette in linear RGB (sky, ground, materials, key and fill colors). One palette for the whole
film; one warm key light and one cool fill; practical lights (lamps, the orb) for the rest.SHOTS: one row per shot with start/end frames, lens in mm, the camera's start and end position in
metres, what it aims at (a moving point or an object), and key, the frame that --stills renders.build_* functions: one per part of the world, in metres, seeded (--seed) so a re-render gives
identical frames.Write the beat sheet first (what happens in each shot, in one line), then turn it into SHOTS. Rebuild the
whole scene from scratch on every run (read_factory_settings(use_empty=True)); never patch a saved .blend.
ground_z in the starter) and build
the mesh from it. Then every tree, rock and path sits on the ground exactly, with no ray casts.bpy.data.objects.new(name, proto.data)), then delete the prototype. The starter places 420 trees this way.Base Color, Roughness, Emission Color
and Emission Strength. Dark albedos (below 0.05) read as black under a grazing sun; start near 0.1.marker.camera = cam. Keyframes from
keyframe_insert are Bezier and already ease in and out.mux.sh takes any audio.--stills --draft: one quarter-size still per shot (under 1 s each after the first run). Look at them.--stills at full size: show the person and get a yes before any animation.--draft: every frame at quarter size, then scripts/sheet.sh render/draft 12 makes a contact sheet of
every 12th frame. Check: the camera never clips through geometry, nothing pops or flickers, no shot is
empty, exposure holds across cuts, the subject stays in the frame.blender -b --factory-startup -P film.py -- --out render/final, or --shot <name> to redo one shot.
Frames are PNGs, so a crash keeps every finished frame and one shot can be redone alone.scripts/mux.sh render/final film.mp4 [music.mp3] encodes H.264 CRF 18, cuts the music to the film, fades
it out over the last second and normalizes it to -14 LUFS.The builder never grades its own work (a rule that spread with Fable 5.2 prompts such as @everestchris6's).
| Eevee | Cycles | |
|---|---|---|
| Starter at 1920×1080 | 2.9 s/frame (96 samples, with haze) | not practical with haze |
| One 960×540 still, haze on | under 1 s | 3 min 16 s (64 samples, Metal GPU, includes the first kernel compile) |
| One 960×540 still, haze off | under 1 s | about 1.5 s (48 samples, denoised) |
| Whole film at 960×540, haze off (216 frames) | 2 min 29 s (0.7 s/frame) | 8 min 19 s (2.3 s/frame, 48 samples) |
| Use for | stylized, low-poly, toon, drafts, most finals | glass, caustics, photoreal interiors, product shots |
Volumes are what make Cycles slow: drop the haze (--no-haze) or render Cycles finals on a GPU farm.
film.py --engine cycles switches Cycles to the GPU backend the machine has (Metal, OptiX, CUDA, HIP,
oneAPI); with --factory-startup it would otherwise render on the CPU.
build_haze), and raise
scene.eevee.volumetric_end past the set (default 100 m) or the far sky shows a clean band.obj.visible_shadow = False on the orb, bulb or lantern.action.fcurves no longer exists (Blender 5 actions have layers and slots). To edit curves use
bpy_extras.anim_utils.action_get_channelbag_for_slot(obj.animation_data.action, obj.animation_data.action_slot).fcurves, or avoid it: default keys already ease.BLENDER_EEVEE in 5.x and was BLENDER_EEVEE_NEXT in 4.2–4.x. Read the
enum instead of hard-coding it (the starter does).Emission Color since 4.0 (older scripts set Emission).Material.use_nodes and World.use_nodes print deprecation warnings in 5.x; they still work until 6.0.Short briefs that work as one prompt (fill the brackets; ask the section 1 questions first):
Make a [20]-second [16:9] film in Blender, entirely in Python, run headless. Low-poly storybook look,
flat shading, warm practical lights, soft haze. Story in [4] shots: [one line per shot]. One palette:
[cream, teal, warm orange]. Every model, material and texture from code, nothing downloaded. Stills of
every shot first; a fresh critic reviews them before any animation. Then a quarter-size draft and a contact
sheet, then the final at 1920x1080, then an MP4 with [a calm piano bed from varg].
Make a 15-second 90s-style toy commercial in Blender with Python: [the toy] on a turntable, a hero push-in,
two close-ups of [features], a glow moment, then a packshot. Plastic materials with clear-coat, a
glossy studio floor, three-point light plus one colored rim. No real brands. Stills first, critic loop, then
render and mux with an upbeat jingle bed.
Make a music video in Blender for [song.mp3]: measure the BPM, cut on the downbeats, drive the lights and one
hero object's scale from the kick. [Theme], [palette], [3-6] shots. Contact sheet every 12th frame before
the final render.
scripts/film.py: the starter film (world, shots, render modes --stills, --draft, --shot,
--engine cycles, --samples, --percent, --no-haze, --seed). Replace the world and SHOTS with yours.scripts/sheet.sh: contact sheet of every Nth frame (frame numbers when ffmpeg has drawtext).scripts/mux.sh: frames (+ music) to MP4.Related: code-to-video-previz (a Blender or three.js blockout that drives Seedance),
code-game-trailer, code-3d-explainer, model-split-screen (Fable vs Opus, Eevee vs Cycles),
video-sound, varg-ai.