Forge render
Forge suite — headless rendering engine and QA eyes. Drives Blender (Cycles/Workbench) to produce render outputs without a GUI: beauty stills, render passes/AOVs (normals, depth, AO, wireframe, UV checker), turntable sequences, 6-view orthographic sheets, and assembled contact-sheet PNGs that the model reads back to verify geometry, shading, and UV quality. Use whenever rendering a 3D asset to PNG, generating a QA contact sheet, setting up Cycles passes, enabling AOVs, doing a turntable render, checking normals or wireframe headlessly, verifying materials or UV unwraps visually, or running any render → Read → critique → fix loop. Triggers: "render the model", "turntable", "contact sheet", "wireframe render", "normal pass", "AO pass", "render passes", "headless render", "Cycles render", "QA render", "render and check", "AOV", "render to PNG". HEADLESS-ONLY: driven from code, output verified by reading a PNG. Part of the Forge suite.From its SKILL.md
npx -y skills add luminary19/atelier --skill forge-renderAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
10.1 KB, ~2.3k tokens by cl100k_base, as published. Nobody here has run it
forge-render — Headless Render + QA Eyes
The render-in-the-loop layer. Every Forge build cycle ends here: emit a render, read the PNG, critique vs brief, fix or advance. This skill drives that loop from code with no GUI.
Project memory: if
FORGE.mdexists at the project root, read it first — it carries the render engine, sample counts, output paths, and coordinate system for this project. Honor those settings; do not override them without a reason.
Suite map
forge (router) → dispatches here via forge-lookdev agent. This skill is called by:
forge-material— after shader authoring, for material QA previewforge-texture— baked maps verified by rendering with the texture appliedforge-light— lighting rig validation (beauty render comparison)forge-uv— UV checker pass is the primary unwrap QA outputforge-validate— invokes this skill's contact-sheet mode as the visual gateWhen the model hands off to another skill, Run = call the Skill tool with its exact name. Writing "now run forge-validate" in prose runs nothing.
Atelier connection: rendered hero stills feed
atelier-webglas poster fallbacks (public/forge/<slug>-hero-poster.webp). The web-runtime/a11y gate isatelier-perf-a11y's job — invoked downstream viaSkill("atelier-perf-a11y")afterforge-optimizepackages the GLB + poster (forge-render does not own that call). For art-direction moodboards from rendered output, seeatelier-direction.
Decide first: engine + availability
Before any render attempt:
- Check FORGE.md for
## Rendersection (engine, samples, output path). - Verify Blender exists — run
scripts/preflight.py --jsonto confirmblenderis found and captureblender_path. (forge-render ships its ownscripts/preflight.py— a focused Blender + Pillow check that returnsblender_path; the router'sforge/scripts/probe.pyis the broader project-state probe. This skill only needs preflight.) - Pick the render mode:
| Goal | Engine | Rationale |
|---|---|---|
| Iterative QA (geometry, normals, wireframe) | BLENDER_WORKBENCH | Headless-safe on Windows, ~1 s/frame, no GPU needed |
| UV checker pass | CYCLES CPU 16 samples | Workbench ignores shader nodes; Cycles respects UV mapping |
| Normal pass (world-space) | CYCLES CPU 1 sample + compositor | Accurate per-pixel world normals |
| Beauty / material hero render | CYCLES GPU (OptiX) or CPU fallback | Physically correct; AgX color management |
| Full contact-sheet QA | Workbench + selective Cycles | Combine both above |
EEVEE Next is UNSUPPORTED headless on Windows. Never use BLENDER_EEVEE_NEXT or
BLENDER_EEVEE as the engine for any headless render. Use Cycles (CPU or GPU) for all
passes requiring node-material evaluation, and Workbench for fast geometry diagnostics.
GPU activation (Cycles): GPU devices are NOT auto-activated in headless mode. Always
call prefs.refresh_devices() (Blender 4.x) before setting cycles.device = 'GPU'.
See references/cycles-gpu-passes.md §GPU for the exact pattern.
The flow
-
Read FORGE.md (if present) — extract engine, samples, output path, slug.
-
Preflight — run
scripts/preflight.py --json. Confirm Blender is found; determine the Blender path for all subsequent subprocess calls. If missing, surface the install URL and stop. -
Write the render script — compose
render.pyor a targeted diagnostic script from the patterns inreferences/cycles-gpu-passes.mdandreferences/workbench-diagnostic.md. Key non-negotiables every script must follow:- UTF-8 stdout wrapper at the top
--factory-startupfor determinism--python-exit-code 1so Python errors fail the Blender process- Absolute forward-slash paths in
scene.render.filepath(never//relative) -f 1(or-a) as the last Blender argumentpathlib.Path(out_dir).mkdir(parents=True, exist_ok=True)before renderbpy.ops.render.render(write_still=True)— withoutwrite_still, no file is saved
-
Invoke Blender (PowerShell):
$BLENDER = $env:BLENDER_EXE # set by preflight or FORGE.md & $BLENDER -b --factory-startup --python-exit-code 1 -P "scripts/render.py" -- <args>Full invocation reference:
references/cli-invocations.md. -
Verify output — check the PNG exists and is >1 KB. A <1 KB PNG is almost certainly an error image (Blender writes a minimal stub when it fails silently).
-
Read the PNG — call
Readon the output path. Visually inspect:- Turntable: silhouette consistency, no floating geometry, scale vs brief
- Wireframe: edge density, no poles >6, no N-gons on SDS surfaces
- Normals (RGB): smooth color gradients; abrupt reversals = flipped normals
- UV checker: uniform checker scale = even texel density; distorted squares = stretching
- Matcap: smooth shading flow; black patches = inverted normals
- Beauty: no fireflies, correct color transform (AgX), transparent background if RGBA
-
Assemble contact sheet (multi-pass QA) — if running a full QA suite, after all individual renders complete, run
scripts/contact_sheet.pyto tile them (PowerShell backtick continuation):python "skills/forge-render/scripts/contact_sheet.py" ` --input-dir C:/forge/out/qa --output C:/forge/out/qa_sheet.png --cols 4The cap is enforced: >36 tiles auto-splits into numbered sheets (
qa_sheet_01.png,qa_sheet_02.png, …) —Readeach one. Override with--max-per-sheet N. ThenReadthe contact sheet PNG(s). -
Decide: iterate or advance — if defects found, amend the geometry/material script (via the responsible skill) and loop back to step 3. If clean, advance to the next pipeline stage. For hard validation, call
Skill("forge-validate").
Render modes in detail
Quick geometry QA (Workbench, <5 s total)
Turntable + wireframe + matcap in one Blender invocation. The fastest read of asset health.
Full pattern: references/workbench-diagnostic.md §turntable.
Passes + AOVs (Cycles compositor)
Enable per-pass toggles on bpy.context.view_layer before the render call. Passes not
enabled at render time cannot be recovered. Route each pass to a separate File Output node.
Critical: keep scene.render.filepath on a different stem from compositor fo.base_path
or they overwrite each other.
Full pattern + gotcha table: references/cycles-gpu-passes.md §passes.
Normal pass (world-space → PNG)
Use Cycles CPU, 1 sample, compositor: Normal pass → multiply 0.5 → add 0.5 → File Output.
Do not use CompositorNodeNormalize — it acts on pixel min/max, not on the [-1,1] theoretical
range. Full remap pattern: references/cycles-gpu-passes.md §normals.
Contact-sheet assembly
scripts/contact_sheet.py tiles all PNGs in a directory into a single labelled sheet.
Degrades gracefully when Pillow is absent (emits a plain text manifest instead). Two
enforced ceilings keep the result Read-friendly: cell cap 512×512 px, and 36 tiles per
sheet (--max-per-sheet, default 36) — beyond that it auto-splits into numbered sheets.
Full usage + layout spec: references/contact-sheet.md.
Operating principles
- Verify, don't assume. Every render attempt must be followed by a file-existence check
and a
Readof the output PNG before reporting success. A zero-KB file is a silent failure. - Workbench first, Cycles only when needed. Workbench is headless-safe on Windows and ~60× faster than Cycles for geometry QA. Use Cycles only for node-material passes (UV checker, normals) and final beauty renders.
- Absolute forward-slash paths everywhere.
scene.render.filepathandfo.base_pathmust use forward slashes (e.g.C:/forge/out/frame_####). Backslashes in Blender Python strings are escape sequences; they silently produce wrong paths. - Scripts, not inline code. All render logic lives in
scripts/; SKILL.md code blocks are illustration only — the model pre-evaluates$()expressions it sees in Markdown, so never rely on them for real execution. - One earned read per loop. Each iteration renders, reads the PNG, critiques against the brief, and makes a single clear fix decision. Do not accumulate multiple unread renders before inspecting.
- Deterministic rebuilds. The Cycles seed is pinned to 0 by default (
--seed Nto change) and--clean(on by default) clears this skill's prior output stems first, so two builds of the same scene produce byte-comparable renders and stale frames never leak into a contact sheet.render.py --jsoncarries ahealthfield (per-file exists / size / blank-frame check) — let the loop iterate-or-advance on that signal, not on prose.
What ships with it: 7 files
110.9 KB alongside SKILL.md, 3 of them executable
references/
- cli-invocations.md10.7 KB
- contact-sheet.md9.3 KB
- cycles-gpu-passes.md19.4 KB
- workbench-diagnostic.md15.1 KB
scripts/
- contact_sheet.pyruns12.5 KB
- preflight.pyruns5.7 KB
- render.pyruns38.4 KB