Skip to content
Design
Skill

/render

Renders photoreal images and videos of a text-to-cad model, a STEP or an xbf with Blender, for people to look at, such as a hero shot, a README picture, a product post, a turntable or a film of a model's motion or animation. Exports a GLB, loads it with cad.blender, lights and

From plugin
text-to-cad
26k8 skills

Claude Code

$ npx -y skills add earthtojake/text-to-cad --skill render --agent claude-code

SKILL.md

render.SKILL.md
name: render
description: Renders photoreal images and videos of a text-to-cad model, a STEP or an xbf with Blender, for people to look at, such as a hero shot, a README picture, a product post, a turntable or a film of a model's motion or animation. Exports a GLB, loads it with cad.blender, lights and frames it in a bpy script that `cad run` runs, drafts in EEVEE and finishes in Cycles on the GPU, and can save a .blend. Not for checking geometry, which a snapshot does.
license: MIT
metadata:
  repository: earthtojake/text-to-cad

Renders for people

A render is a picture for a person: a hero image, a README picture, a post, a turntable, a film of a mechanism. The model goes to Blender as a GLB, loaded by `cad.blender.load`; the scene (camera, lights, world, engine, output) is an ordinary Python script that imports `bpy`, Blender as a Python module, and `cad run` runs it. Judge geometry with `cad model snapshot`, never with a render: a render's lens, light and depth of field make it a poor measure, so never read a dimension off one.

Start with the task

| Task | Start with | Reference | | --- | --- | --- | | **A still of a model** | Export a GLB, write a `render.py` that loads it, `cad run render.py`. | [The script](#the-script), [scene script](references/scene-script.md) | | **Draft, then a final** | An EEVEE draft at 1080p, looked at, before Cycles. | [Draft then final](references/shots.md#draft-then-final) | | **A pose of a motion or a frame of an animation** | `model.play(name)` and the frame. | [Clips](#load-the-glb) | | **A turntable** | The camera on an empty that turns once. | [Turntables](references/shots.md#turntables) | | **A film of a motion or an animation** | `model.play(name)`, then an mp4. | [Films](references/shots.md#films) | | **Motion blur, depth of field, a glow** | The scene's and the camera's settings; a keyed emission. | [Shots](references/shots.md) | | **Choose looks** | `cad.build123d.materials` in the model. | [Looks](#looks) | | **Give the person a .blend** | `bpy.ops.wm.save_as_mainfile` at the end of the script. | [A .blend](references/shots.md#a-blend-for-a-person) | | **Use the GPU** | Cycles' device, chosen in the script. | [Engines](references/scene-script.md#engines-and-the-gpu) |

Setup

Run the `cad` command (`~/.local/bin/cad` where it is not on your PATH; `cad.exe` on Windows). If it is missing, install text-to-cad, outside a sandbox or with its permission:

curl -fsSL https://texttocad.dev/install.sh | sh

On Windows, in PowerShell: `irm https://www.texttocad.dev/install.ps1 | iex`. If the CAD app was only just added, its server may still be starting: try again for up to a minute first. `cad doctor --check` explains any other failure, changing nothing; `cad doctor` repairs what it reports. Tell the person any next step `cad setup` prints.

`cad run render.py` sees `import bpy` and gives the script cad's blender integration: an environment on Python 3.13, the one Blender is built for, holding bpy 5.2.3 (Blender 5.2 LTS) beside cad, made the first time and kept. The script imports what it likes of cad and build123d beside bpy, so one script can build a model, export it and render it. Blender's own preferences, add-ons and extensions folders are cad's, never the person's, so their Blender settings never load into a run; every `cad run` shares them, so an extension or a preference one script installs or saves is there for the next, and a script that needs one sets it up itself. bpy has no build for Intel Macs or Linux on ARM, where `cad run` refuses such a script by name. A `--python` or a header's `requires-python` that leaves 3.13 out is refused the same way; one that admits it (`--python 3.13`) runs on the same environment as none. Nothing here starts the Blender app.

Export the model

cad model export "$ID" scene.glb --tolerance 0.02 --angle 5

`ID` is the model's id (running its script prints it); a STEP or an xbf exports the same way (`cad step export part.step scene.glb --tolerance 0.02 --angle 5`). The GLB is in metres, Z up once imported, with the assembly's tree as nested empties, a PBR material per look, and each motion and `animation()` as a clip. The viewer's mesh shows its facets in a path tracer or a close camera: `--tolerance` (mm, absolute) and `--angle` (degrees, 1 to 28.5) mesh this file finer, for it alone. The cost is triangles and seconds: a tenth of the tolerance is about three times the segments round a curve and ten times the triangles of a doubly curved face. Start at 0.02 mm and 5 degrees for a close-up of a hand-sized part and coarser for a large assembly seen whole, and export finer when a draft shows facets. Say the file's size when it is large. Export again after every model change: the GLB is a copy.

The script

# render.py: cad run render.py
import math
from pathlib import Path

import bpy
from mathutils import Vector

from cad.blender import load

HERE = Path(__file__).resolve().parent

bpy.ops.wm.read_factory_settings(use_empty=True)  # no person's startup file, no default cube
scene = bpy.context.scene
model = load(HERE / "scene.glb")  # every part where cad placed it

scene.render.resolution_x, scene.render.resolution_y = 1920, 1080
aim = bpy.data.objects.new("aim", None)
aim.location = model.center
camera = bpy.data.objects.new("camera", bpy.data.cameras.new("camera"))
camera.data.lens = 85
view = math.tan(camera.data.angle / 2) * min(1, scene.render.resolution_y / scene.render.resolution_x)
distance = model.size.length / 2 / view * 1.1  # the whole box in the frame's shorter side
camera.location = model.center + distance * Vector((1, -1, 0.6)).normalized()
camera.constraints.new("TRACK_TO").target = aim
sun = bpy.data.objects.new("sun", bpy.data.lights.new("sun", "SUN"))
sun.data.energy, sun.rotation_euler = 3.0, (0.8, 0.2, 0.6)
for item in (aim, camera, sun):
    scene.collection.objects.link(item)
scene.camera = camera
scene.world = bpy.data.worlds.new("
Read more
@earthtojake
Ships withtext-to-cad

Design physical products with AI

Stars on GitHub

Momentum

stars in total
26.3k
Star history of earthtojake/text-to-cad on GitHub, a chart by star-history.com

Other skills on text-to-cad.

cad

cad

Creates and edits parametric CAD parts, assemblies and 2D profiles as Python build123d models that text-to-cad's server builds…

fea

fea

Checks whether a part or an assembly of bonded parts holds under its loads, as a linear static stress study of a STEP, an xbf or…

pcb

pcb

Create, edit, lay out and review native KiCad circuit boards (.kicad_pcb) and their schematics (.kicad_sch) - parts and nets,…

print3d

print3d

Prints a part - slices an `.stl`, `.3mf` or `.obj` into printer-ready G-code with OrcaSlicer, headless or in the app, with…

robot-simulation

robot-simulation

Robot and world descriptions (URDF, SRDF, MJCF) for ROS, MoveIt and MuJoCo. Use to generate a robot description or a MuJoCo scene…

More skills from other plugins.

impeccable

impeccable

Use to design, redesign, critique, audit, polish or animate a frontend: websites, landing pages, dashboards, app UI, components,…

@pbakaus@pbakausInstall Skill

Questions about render.

Which coding agents can use render?
render installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.