3D Image Renderer

SkillWeb & browsing

Generate PNG images by building a real Three.js 3D scene and capturing one frame headlessly — no image model involved. Takes a text prompt and an aspect ratio (1:1, 16:9, or 9:16) and produces a rendered PNG. Use this skill whenever the user asks to generate, create, or render an image, picture, scene, wallpaper, thumbnail background, or product shot with this system — especially with phrases like "generate an image of", "render a scene", "create a PNG", "no image model", "3D render of", or a prompt paired with an aspect ratio. Also use it when the user wants an image in a named visual style (dark studio, Apple light, nature, sunset, night, underwater). Not for editing existing images, 2D vector art, or animated video (VidTSX handles video).

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the 3D Image Renderer skill

What this skill tells your AI

The instructions your AI receives, as published by hassancs91/claude-image-generation in .claude/skills/level-2-image-generator/SKILL.md and read by ahel’s review.

Renders a text prompt into a PNG by writing a Three.js scene and capturing one frame with headless-gl under Xvfb. Think of every image as frame 0 of a TSX animation composition: deterministic, seeded, time = 2.0s.

Inputs

  • prompt — what to render
  • aspect ratio — one of 1:1 (1080×1080), 16:9 (1920×1080), 9:16 (1080×1920). Default 16:9 if unspecified. No custom sizes.

Workflow (follow in order)

1. Setup

bash <skill_dir>/scripts/setup.sh

Idempotent; instant when cached. Installs npm deps into /home/claude/scene-render/ and drops the bundled prebuilt gl binary in place (compiles from source only if the binary fails its smoke test). It also copies pipeline.mjs and validate.mjs into the workdir. If it prints SETUP FAILED, report the error to the user — do not hand-roll a fallback.

2. Plan the scene

  • Pick ONE style preset → read references/style-presets.md now.
  • List the hero elements: every concrete noun in the prompt ("headphones", "tree", "flowers") is a hero element.
  • Read references/geometry-recipes.md for any element it covers before inventing geometry.

3. Write the scene

Create /home/claude/scene-render/scene.mjs. Import ONLY from the local pipeline — never re-implement renderer setup, pixel readback, or PNG writing:

import {
  THREE, createRenderer, captureFrame, addStudioEnvironment,
  seededRandom, visibleHeightAt,
} from './pipeline.mjs';

const time = 2.0; // the captured "frame"
const { renderer, glContext, W, H, OUT_W, OUT_H } =
  createRenderer('16:9', { exposure: 1.15 /* from style preset */ });

const scene = new THREE.Scene();
// ... build: sky, lights, ground, hero elements (per preset + recipes) ...

await captureFrame({
  renderer, glContext, scene, camera, W, H, OUT_W, OUT_H,
  outPath: '/home/claude/scene-render/out.png',
});
console.log('DONE');

Scene-authoring rules:

  • All randomness via seededRandom(seed) — never Math.random().
  • InstancedMesh for anything repeated 50+ times; per-instance color via setColorAt + instanceColor.needsUpdate = true.
  • Bake rotations into geometry (geometry.rotateZ(...)) — do not stack Euler rotations on meshes for construction.
  • Validate every horizon/background element with visibleHeightAt (the FOV rule in geometry-recipes.md) BEFORE rendering.
  • No post-processing. Glow = emissive + additive blending + fog.
  • WebGL1 only: no transmission, no WebGL2-only features, three stays at 0.152.2 (pinned by setup — do not upgrade).

4. Render

cd /home/claude/scene-render && xvfb-run -a node scene.mjs

5. Validate (mandatory — never skip)

Write a hero spec covering each prompt-named element with its dominant material color, then:

node validate.mjs out.png heroes.json
[
  { "name": "flowers", "hex": "f5a8c8", "tolerance": 45, "minPct": 0.3 },
  { "name": "tree canopy", "hex": "5a9440", "tolerance": 60, "minPct": 2.0 }
]

Also open the PNG with the view tool if image viewing works in this session. If it returns placeholders, rely on the validator output (histogram, ASCII map, presence checks) — it was designed for exactly that.

Fix and re-render when:

  • any hero element FAILs presence (typical fixes: more instances, bigger scale, camera reframe, contrasting material)
  • WASHED OUT / TOO DARK / LOW CONTRAST warnings (typical fixes: exposure and ambient per the style preset table; in light styles swap pure-white materials for metallic/mid-gray)
  • the ASCII map shows a composition failure (subject cropped, background walling off the sky)

Maximum 2 fix iterations, then deliver best result and tell the user what still needs work.

6. Deliver

cp /home/claude/scene-render/out.png "/mnt/user-data/outputs/<descriptive_name>.png"

Present the PNG with present_files. Keep the summary short: style preset used, hero elements, and any validation fixes applied. Only include scene.mjs in the delivery if the user asks for the code.

Hard rules (violating any of these produced real failures)

  1. three@0.152.2 pinned — r163+ drops WebGL1 and headless-gl is WebGL1-only.
  2. Pixel readback needs vertical flip + alpha forced to 255 (pipeline does it).
  3. No MSAA headless — SSAA 2× via the pipeline is the anti-aliasing.
  4. Light styles: exposure ≤ 1.08, ambient ≤ 0.35, and the hero MUST include a metallic or mid-gray material. Pure white on white is invisible.
  5. Background elements sized by intuition WILL wall off the sky — run the FOV check.
  6. Prompt-named elements must pass the presence validator before delivery.
  7. Everything deterministic: seededRandom, fixed time = 2.0.

Signals

GitHub stars
92
Forks
57
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
x-3d-image-renderer
Source
github.com/hassancs91/claude-image-generation