---
name: Img2threejs
slug: img2threejs
category: Frontend
description: Img2threejs turns a reference image into a code-only, procedural Three.js model using a staged sculpting pipeline with quality gates and an AI-vision self-correction loop. Use it when you need an animation-ready 3D asset, character model, or material study rebuilt from a photo rather than photogrammetry or mesh extraction.
github: "https://github.com/img2threejs/img2threejs"
language: Python
stars: 11756
forks: 915
install: "npx degit https://github.com/img2threejs/img2threejs ~/.claude/skills/img2threejs"
installs_to: ~/.claude/skills/img2threejs
source_path: SKILL.md
collection_size: 2
category_size: 567
collection_url: "https://dirskills.com/collections/img2threejs/img2threejs"
added: 2026-08-15T06:50:02.430Z
last_synced: 2026-08-15T06:50:02.430Z
canonical_url: "https://dirskills.com/skills/img2threejs"
---

# Img2threejs

Img2threejs turns a reference image into a code-only, procedural Three.js model using a staged sculpting pipeline with quality gates and an AI-vision self-correction loop. Use it when you need an animation-ready 3D asset, character model, or material study rebuilt from a photo rather than photogrammetry or mesh extraction.

**Install:**

```bash
npx degit https://github.com/img2threejs/img2threejs ~/.claude/skills/img2threejs
```

## README

# img2threejs — Image to procedural Three.js

Rebuild the object visible in a reference image as a **code-only** procedural Three.js model,
gated by a staged sculpting pipeline and an AI-vision self-correction loop. This is
reconstruction-by-code, **not** photogrammetry, mesh extraction, or downloaded art packs.

Agent-agnostic: works under Claude Code, Codex, or OpenCode. Wherever this doc says "agent
vision" or "agent browser tool", use whatever the host provides — native image reading, a
browser MCP (playwright/chrome-devtools), the project preview, or a user-supplied screenshot.

## Canonical shared checkout

Keep one checkout of this repository and let every host enter it through a symlink, so Claude and
Codex execute the same code instead of drifting apart:

```text
~/.claude/skills/img2threejs -> <your checkout>
~/.codex/skills/img2threejs  -> <your checkout>
```

## When To Use

The user attaches/points to an object image and wants a procedural Three.js model, a
reconstruction/animation/destruction plan, a sculpt spec, or code. Also for material studies,
action-ready props, game objects, botanical/mechanical parts, and stylized reconstructions.

## Core Promise

Sculpt from a photo, in order — never one-shot a mesh:
1. **Run `python3 forge/next.py <spec>` first, or `python3 forge/next.py --state .img2threejs/state.json`.** The state form reports the ordered local checklist, exact next command, evidence status, and bounded correction-loop status; it never replaces the spec/pass gates.
1. **Use local state first.** Initialize it once, then run
   `python3 forge/next.py --state .img2threejs/state.json [<spec>]` at every start/resume and before
   every correction iteration. Obey a hard stop; never continue from memory.
2. **Validate** the image is a suitable 3D target (`grimoire/intake/validation_rubric.md`).
3. **Assess** object class + complexity, then write a `qualityContract` before any code.
3. **Spec** it: component hierarchy, materials, lighting, pivots, sockets, action anchors.
4. **Build pass-by-pass** from blockout → structure → form → material → lighting → interaction → optimization.
5. **Verify** each pass with a screenshot compared against the reference; fail a pass if an identity-defining feature is wrong even when the global score looks fine.

State explicitly when output is approximate/stylized/low-poly. A single image cannot reveal
hidden sides or guarantee exact geometry — say so instead of faking confidence.

## Resumable local workflow

For a cross-agent or multi-session reconstruction, initialize the local state before intake:

```bash
python3 forge/state.py init --reference <image> --profile character --spec object-sculpt-spec.json
python3 forge/next.py --state .img2threejs/state.json
python3 forge/state.py mark image-analysis --evidence analysis.md
```

`generic`, `character`, and `cs2` profiles insert their required intake gates in order. Every
completed step needs evidence; every skipped step needs a reason. The state file is a resumability
index, not visual evidence: renders, specs, review history, and deterministic gates remain the
authoritative artifacts.

## Transparency and Process Debugging (Critical — from Bowie Knife reconstruction)

**The problem:** When the user cannot tell what was done or where something went wrong, they cannot debug the process. Over-claiming (reporting success when features still don't match) destroys trust and makes iterative improvement impossible.

**Rule:** Be transparent + don't over-claim. State exactly what changed each pass, with evidence, and name what still doesn't match:
- After each pass, explicitly list what changed: "Updated guard shape to extend left edge from -0.56 to -0.48 for handle overlap"
- Provide evidence: reference the specific values, coordinates, or parameters that changed
- Name what still doesn't match: "Handle silhouette traced but still flat plane (no Z palm-swell), procedural crosshatch not reference's exact dot-grid knurl"
- Explain why a change was made: "Extended guard left edge because handle ends at X=-0.42 and guard ended at X=-0.20, causing visual gap"
- Never claim a feature is "done" when it's only "improved" — use precise language
- When a gate passes but visual inspection shows issues, explain the limitation: "2D gate passed (fidelity 0.83) but three-quarter render shows blade reads as toy (no grind wedge) — 2D gates are blind to 3D realism"

**The user needs to be able to debug the process, not just the output.** If something is wrong, they should be able to trace which decision led to the error and correct it. Opaque processes force restarts; transparent processes enable refinement.
## Transparency and Process Debugging

Report what changed each pass with evidence (exact values/coordinates), name what still doesn't
match, and never claim "done" when only "improved". A passing gate is not proof of 3D realism.
Full rule + examples: `grimoire/review/self_correction.md`.

## GLB-mediated v2 render-fidelity track (1.5 alpha)

When the user supplies a GLB as an intermediate reference, use the browser-rendered GLB
as the structural and visual baseline, then author an independent procedural factory. The
raw GLB is never pixel evidence and its topology/materials are never copied into the factory.

Before any factory edit:

1. Run `forge/stage1_intake/probe_glb.py` and inspect `semanticDecomposition`. A merged
   one-node/one-mesh/one-primitive/one-material asset is `insufficient` for reliable semantic
   labels; connected-component/curvature/normal/UV segmentation is hypothesis evidence only.
   Request a multipart GLB or capture a browser semantic-ID pass before claiming exact regions.
2. Author and validate one shared `render-profile.v2` with
   `forge/stage4_review/validate_render_profile.py`. Both GLB and procedural routes must use
   the same output color space, linear working space, tone mapping/exposure, PMREM environment,
   viewport/DPR, camera, background and lighting settings.
3. Capture six passes for every admitted view: `beauty`, `alpha-silhouette`, `semantic-id`,
   `depth`, `normal`, and `roughness-material-id`. Use
   `forge/stage4_review/compare_region_passes.py` for deterministic global/per-region evidence;
   missing semantic-ID data blocks per-region confidence instead of falling back to whole-image
   color or silhouette scores.
4. Use region-specific continuous geometry/material strategies. Do not replace a face/head volume,
   cloth shell, kasa, staff, or tail with a generic collection of floating primitives when the
   region's silhouette or attachment requires a continuous surface.
5. Run one correction group per loop in this order: `camera → silhouette → face → clothing →
   accessory → materials → lighting`. Recapture the full pass set after each group and record
   the changed group, hashes and score. Never combine groups when diagnosing improvement.

The machine-readable contract lives in `docs/specs/render-profile.v2.schema.json` and
`docs/specs/render-profile.v2.example.json`. The executable manifest bridge accepts
`--render-profile` and exposes `record-pass`; its `glb-mediated-v2` validation is fail-closed.

## Required Inputs

- one image path / screenshot / URL / attached image (if missing or unreadable, ask)
- intended use: prop, game object, hero render, playable/destructible object, animation rig
  (default: real-time browser prop with interactive performance)
- for a CS2 request, an authoritative classification record (family/subtype and evidence refs) or
  an explicit request for the user/vision provider to supply one; heuristic detection alone is not
  enough to select a geometry adapter

## Mandatory Local State Gate

Conversation context is disposable; `.img2threejs/state.json` is the local checklist authority.
Initialize it once per reconstruction:

`python3 forge/state.py init --state .img2threejs/state.json --reference <img> --profile <generic|cs2|character>`

At every fresh start, resume, or correction loop, run
`python3 forge/next.py --state .img2threejs/state.json [object-sculpt-spec.json]` before touching
code. It prints the current step, pass, incomplete mandatory steps, exact next command, and
`loop/max`. Exit code 3 or `status=stopped` is a hard stop: report the reason and request input.
Never bypass it by reconstructing progress from chat history.

After evidence exists, record it with
`python3 forge/state.py mark <step-id> --state .img2threejs/state.json --evidence <path>`.
Mark a non-applicable step `skipped` only with `--reason`; silent omission is forbidden. Loop counts
are derived from `reviewHistory` actions `refine-spec`/`refine-code`, not agent memory. Defaults are
3 corrections per pass and 6 total.

Profiles add mandatory gates rather than changing the core order: `cs2` requires classification,
manifest, and a machine-readable CS2 review before AI review; `character` requires the character
contracts and landmark evidence. Every profile records suitability, projection applicability, and
material-evidence applicability; conditional steps require evidence or an explicit skip reason.

## The Loop (scripts do enforcement; agent vision does judgment)

Run scripts from the skill root (`forge/...`). Pure Python 3.10+ stdlib, no pip installs.
Full flags: `grimoire/scripts.md`. Never let a script *score* visuals — that is the agent's job.

1. **Analyze the image first** (agent vision, before any script): work the layered observation
   protocol in `grimoire/intake/image_analysis.md` — identify/classify, decompose macro→meso→micro,
   map part relationships, name materials in PBR terms, list identity-defining features, and flag
   what the single view hides. Observation before inference; controlled 3D vocabulary; 3D
   object-space not 2D image-space. This is generic for any subject and feeds every field below.
   Then probe local images: `forge/stage1_intake/probe_image.py <image>` (metadata only, not a visual check).
1a. **Local Spec Search** — after image analysis and before writing or refining a spec, local
    evidence is a pipeline stage, not an optional memory lookup, whenever the request needs
    domain-specific anatomy, PBR, wear, geometry, runtime, or physics specifications. The pre-spec
    command automatically runs BM25, chooses `cs2` for CS2 targets and `core_3d` otherwise, and
    writes a `localSpecSearch` evidence bundle into the assessment:
    `python3 forge/stage2_spec/new_pre_spec_assessment.py "Name" --image <img> --out assessment.json`.
    Add observed terms with repeatable `--spec-query "<term>"`; use `--collection <collection>` only
    when the automatic collection choice is insufficient. `new_sculpt_spec.py --assessment` carries
    that bundle into the final spec, including snippets, `source_refs`, and `evidence_refs`.
    For extra focused retrieval, the direct CLI remains available:
    `python3 forge/stage1_intake/search_specs.py "<query>" --collection <collection> --limit 3 --snippet-chars 250 --json`.
    For CS2, include the anatomical and the colloquial name, for example
    `--spec-query "safety ring finger ring"` or `search_specs.py "roughness matte" --collection cs2`.
    Expand queries with object names,
    component names, material/finish terms, behavior terms, and known aliases; retry focused
    alternatives when the first result is incomplete. Build the spec from returned evidence and do
    not invent domain specs when local evidence exists. Search caches are local/generated only;
    preserve JSONL records and source provenance rather than replacing them with cache output.
1aa. **Optional fidelity evidence adapters** — use them only when they improve an observed weak
    point; the stdlib core remains authoritative. Route thin/complex masks to local SAM2, character
    face/pose evidence to MediaPipe, and weak front/back cues to Depth Anything V2:
    `python3 forge/stage1_intake/run_vision_adapter.py <segment|landmarks|depth> ...`.
    Every adapter emits provenance. Confirm SAM2 selected the intended component; treat monocular
    depth as relative only; review landmarks before copying them into anatomy. For browser work,
    prefer Chrome DevTools MCP for live console/network/performance diagnosis, use
    threejs-devtools MCP read-only to inspect scene/material/renderer state, and reserve Playwright
    MCP for cross-browser or host fallback. MCP-only scene mutations never count as implementation:
    write the proven change back to the spec or TypeScript, rebuild, and recapture. Use Context7
    only with the target project's installed Three.js version; local types, typecheck and runtime
    smoke tests override live docs. Full routing and commands:
    `docs/integrations/reference_fidelity_tooling.md`.
1b. **CS2 intake manifest** — for a CS2 request, create and validate `cs2-intake.json` before
    pre-spec authoring. Run admission and probing for every source view, record the heuristic signal
    as non-authoritative evidence, attach the classification record, resolve the supported family,
    and choose `route` independently from `exactnessTier`. Missing classification, insufficient
    coverage, or a contradictory high-confidence class is `request-input`; unsupported families do
    not continue into spec generation.
2. **Pre-Spec Assessment Gate** — classify + score complexity + write the quality contract:
   `forge/stage2_spec/new_pre_spec_assessment.py "Name" --image <img> --complexity <simple|moderate|complex|ultra-complex> --out assessment.json`. Rules: `grimoire/intake/quality_contract.md`.
   Set `objectClass.primaryDomain` (`object` | `character` | `hybrid`) and fill the seeded
   `detailInventory` (its `targetMinDetails` scales with complexity). **Supported CS2 knife skins
   and Glock-18 assets**: always pass `--cs2`, which defaults the complexity tier to `ultra-complex`
   (`targetMinDetails` 16) — the finish/wear/hardware is the item, so CS2 is held to the top
   fidelity bar; `targetMinDetails` never drops below the 9 floor even if downgraded by hand.
   **Author procedural GEOMETRY (blade/guard/grip profiles) but make the FINISH a de-lit
   reference-crop PROJECTION, not a procedural finish material** — projecting the photo's own
   pixels is what reaches reference fidelity for patterned skins (Doppler/Gamma/Marble/Fade), and
   is what the v1.3 baseline demos do; a procedural finish for a patterned skin reads visibly wrong
   against the reference. Take the projection path in step 2c (it generalizes from characters to
   any reference-matched surface). Procedural finish is the fallback ONLY when live view-dependent
   response matters more than matching this one reference. Finish routes + rulebook:
   `grimoire/build/cs2_finishes.md`; optional exact-texture acquisition:
   `grimoire/intake/cs2_texture_acquisition.md`.
1a. **Local Spec Search** — after image analysis, before writing or refining a spec, pull local
    domain evidence (anatomy/PBR/wear/geometry/runtime/physics) rather than inventing it:
    `python3 forge/stage2_spec/new_pre_spec_assessment.py "Name" --image <img> --out assessment.json`
    (auto-runs BM25, auto-picks `cs2`/`core_3d` collection, writes a `localSpecSearch` bundle that
    `new_sculpt_spec.py --assessment` carries into the spec). Full query-expansion recipe
    (bilingual terms, focused `search_specs.py` retrieval, cache rules):
    `grimoire/intake/local_spec_search.md`. MUST read it before retrying an incomplete or
    domain-specific query.
1b. **CS2 intake manifest** — for a CS2 request, create and validate `cs2-intake.json` before
    pre-spec authoring (admission, heuristic signal, classification, family/route resolution).
    MUST read `grimoire/intake/cs2_intake_contract.md` completely before creating the manifest or
    running pre-spec assessment.
2. **Pre-Spec Assessment Gate** — classify + score complexity + write the quality contract:
   `forge/stage2_spec/new_pre_spec_assessment.py "Name" --image <img> --complexity <simple|moderate|complex|ultra-complex> --out assessment.json`. Rules: `grimoire/intake/quality_contract.md`.
   Set `objectClass.primaryDomain` (`object` | `character` | `hybrid`) and fill the seeded
   `detailInventory` (its `targetMinDetails` scales with complexity). **Supported CS2 knife
   skins**: always pass `--cs2`, which defaults the complexity tier to `ultra-complex`
   (`targetMinDetails` 16, floor 9) — the finish/wear/hardware is the item, so CS2 is held to the
   top fidelity bar. Author procedural GEOMETRY but route the FINISH through the projection path in
   step 2c — a procedural finish for a patterned skin (Doppler/Gamma/Marble/Fade) reads visibly
   wrong against the reference. Finish routes + rulebook: `grimoire/build/cs2_finishes.md`;
   optional exact-texture acquisition: `grimoire/intake/cs2_texture_acquisition.md`.
2b. **Detail inventory** (do not skip for detailed subjects) — scan zones and enumerate every
   identity-defining small detail (gloss, bevel, fasteners, linework, contours, stains):
   `forge/stage1_intake/build_detail_inventory.py <image> --mode grid-3x3 --out-dir <dir> --out di.json`.
   Each detail MUST map to a `component.localFeatures` or `material.localOverrides` entry — never
   prose only. Taxonomy + 3D-term recipes: `grimoire/intake/detail_inventory.md`.
2c. **Projection-first fidelity (characters AND reference-matched surfaces — supported CS2 skins, decals,
   painted patterns)** — when the goal is matching a specific reference's surface, put the photo's
   own pixels on the mesh instead of approximating them procedurally. This is the single biggest
   fidelity lever; a procedural material for a patterned surface is the #1 reconstruction failure.
   Recipe (`grimoire/character/likeness_maximization.md` — its two levers, align-mesh+camera and
   project-the-photo, generalize past characters): solve the camera
   (`stage1_intake/solve_camera_pose.py` → `referenceCamera`), **de-light** the reference so it is
   free of baked lighting (`stage1_intake/delight_albedo.py`, hard requirement — this is what makes
   projection safe, not the flat-lit icon), then project the de-lit crop onto the mesh and bake it
   into UVs (`stage3_build/bake_projected_texture.py --mesh-id <id>`). For a CS2 skin the mesh is the
   procedural family-specific component tree you author in the spec, and the projected de-lit crop IS the finish
   (front + back from the two views) — no procedural Doppler material. For characters, first capture
   landmarks (`stage1_intake/extract_landmarks.py --out anatomy.json`), fill `preSpecAssessment.anatomy`,
   route `grimoire/character/reconstruction.md`. A single view cannot show hidden sides — report
   per-region confidence and request more views when it matters.
   Character sub-routes, in the order they are needed — decide what parts exist before shaping any
   of them, and shape the head before the hair that sits on it:
   - **Parts** — `grimoire/character/structure_decomposition.md`: which parts the figure is made of,
     and where each one's boundary falls.
   - **Head** — `grimoire/character/head_construction.md`: skull, face plane and feature placement,
     the sub-route the likeness gate reads against.
   - **Hair** — `grimoire/character/stylized_hair_threejs.md`, with the parameter contract in
     `grimoire/character/threejs_hair_parameter_contract.json`. Lock topology first: material
     tuning cannot repair wrong lock topology, so run it only after the silhouette review passes.
2d. **Reference-free humanoid** — when the request is a generic figure with no reference image
   ("a low-poly humanoid"), there is nothing to measure, so fill anatomy from public canon with
   `forge/stage2_spec/humanoid_proportions.py <spec> --style-heads 8 --in-place`. It writes
   `anatomy.source: "canon-table"` so canon is never mistaken for measured evidence, refuses to
   run at all when the spec names a reference image, and lists what the corpus does NOT supply
   under `anatomy.unsourced`. O
