Forge uv
Forge suite — UV unwrapping, seam placement, island packing, texel density normalization, UDIM tile layout, and distortion/checker verification for 3D assets. Produces a validated UV map (non-overlapping bake channel + layout PNG) that downstream baking, material, and export skills can consume without rework. (The project-wide texel-density BUDGET is set in forge-standards; this skill normalizes a mesh's UVs to hit it.) Use whenever UV unwrapping a mesh, placing seams, packing UV islands, normalizing texel density, setting up UDIMs, checking UV stretch or distortion, generating a UV layout PNG, validating UV overlaps, running a checker-map render, preparing UVs for texture baking, or correcting UV scale before export. Trigger phrases: "unwrap", "UV seams", "pack islands", "normalize texel density", "fix UV texel density", "texel density on a UV map", "UDIM", "UV checker", "UV layout", "UV distortion", "UV stretch", "UV overlap", "UV validation", "bake UVs", "lightmap UV", "UV scale". HEADLESS-ONLY: driven from code (pure `--background` via bpy + bmesh), output verified by reading a PNG. Part of the Forge suite.From its SKILL.md
npx -y skills add luminary19/atelier --skill forge-uvAssembled 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
13.8 KB, ~3.2k tokens by cl100k_base, as published. Nobody here has run it
Forge UV
UV maps are the contract between geometry and texture. Every bake, paint, and export operation
downstream depends on a valid, non-overlapping, correctly-scaled UV layout. This skill owns
that contract — from raw mesh to verified UV PNG — in pure blender --background: unwrap and
projection solvers run headless directly, and the post-process ops that normally need a UV
editor area (pack, overlap check, TD scale) run via operator-free bmesh implementations
(references/seams-packing.md §7/§8, references/texel-density.md §4). The one step that wants
a screen — the optional export_layout reference PNG — degrades to the checker-map render.
Project memory: if
FORGE.mdexists at the project root, read it first — it carries the texel density target, texture resolution budget, target engine, UV channel naming policy, and verified output paths for this project. IfATELIER.mdexists, check the aesthetic and surface-fidelity notes, which drive texel density targets.
Suite map — where this skill fits:
Upstream (must complete first):
- forge-brief — writes FORGE.md with texel density + poly budget targets
- forge-standards — canonical units, scale, naming, and texel density budgets per asset class
- forge-model — clean geometry; applied scale; hard edges set for seam automation
- forge-topology — N-gon cleanup, retopo, decimation — topology must be final before UV
This skill (UV):
- Seams → unwrap → pack → TD normalize → validate → layout PNG
Downstream (consumes this skill's output):
- forge-texture — baking (normal/AO/curvature) requires non-overlapping bake channel
- forge-material — UV maps drive all texture sampling; texel density governs tex resolution
- forge-export — multi-UV-channel export (diffuse UV0, lightmap UV1); FBX/GLB UV naming
- forge-validate — UV overlap gate is part of the full asset validation pass
- forge-render — checker-map render for visual QA
Web handoff: forge-export → forge-optimize → atelier-webgl (R3F / Three.js scene). UVs are upstream of texture and feed the web GLB, so a UV asset bound for the web rides this canonical chain after texturing/validation.
Run = call the Skill tool with the exact name. Writing "now run forge-texture" in prose runs nothing.
Decide first: pick the unwrap method
Before writing any bpy code, choose the method. Wrong choice = re-unwrap later.
| Method | Best for | Seams required? | Speed |
|---|---|---|---|
ANGLE_BASED | Organic meshes, characters, curved hard-surface | Yes | Medium |
CONFORMAL | Quick iterations, background assets, simple shapes | Optional | Fast |
MINIMUM_STRETCH | Hero assets, displacement maps, print | Yes | Slow |
| Smart UV Project | Architecture, hard-surface boxes, no-seam workflow | No | Medium* |
| Cube/Cylinder Project | Box/cylinder primitives, atlases | No | Fast |
| Lightmap Pack | Dedicated lightmap channel (UV1), engine baking | No | Medium |
* Smart UV Project is ~100× slower via Python on meshes >100 k faces (pre-Blender 3.6 solver bug).
Use Blender 4.x. See references/unwrap-methods.md §Gotchas for the workaround.
Verify Blender is available before executing:
# PowerShell — confirm blender is on PATH before proceeding
blender --version
# If missing: winget install BlenderFoundation.Blender
If Blender is absent — degrade, don't dead-end. For the common "no Blender on this box" case there is a real pure-Python fallback for the bake-channel use case:
| Need | Primary (Blender) | Fallback (no Blender) |
|---|---|---|
| Clean non-overlapping UVs for baking | ANGLE_BASED + pack | xatlas (pip install xatlas) → xatlas.parametrize(verts, faces) |
| Seam control / TD craft / UDIM / layout PNG | Blender (required) | not available — needs Blender |
| Checker-map visual QA | Cycles checker render | trimesh + PIL (forge-topology references/mesh-libs.md §7) |
xatlas produces guaranteed non-overlapping atlas UVs headlessly with zero Blender dependency, so
"just need clean UVs for baking" still ships. Seam placement, texel-density normalization, UDIM,
and the layout PNG still require Blender. Full fallback recipe + caveats:
references/xatlas-fallback.md.
If Blender is absent AND the task needs seam/TD/UDIM craft (not just a bake channel), stop and report — xatlas cannot cover those. Document the fallback in a comment whenever you take it.
The flow
-
Read FORGE.md — pull texel density target, texture resolution, UV channel naming, output paths. If absent, use defaults: TD = 1024 px/m, texture = 2048 px, bake channel =
"UVMap". -
Pre-flight the mesh — confirm scale is applied; confirm the mesh exists and has faces. Scale not applied = stop and run forge-topology → apply transforms first. Full pre-flight:
references/preflight.md. -
Choose the unwrap method using the table above. For most game/web props:
ANGLE_BASEDwith seams from sharp edges at 30°. Deep method options:references/unwrap-methods.md. -
Mark seams — for
ANGLE_BASED/CONFORMAL/MINIMUM_STRETCH:- Hard-surface: use
mark_seams_from_sharp(sharpness=radians(30)). - Organic / characters: place seams manually along hidden/back-facing edges.
- Back-propagate after unwrap with
seams_from_islands()to lock the layout. Full seam rules:references/seams-packing.md §Seam placement rules.
- Hard-surface: use
-
Unwrap — run the chosen operator. Always pass
correct_aspect=True. ForMINIMUM_STRETCH, capiterations=500headlessly (unlimited = hangs). Full API signatures:references/unwrap-methods.md. -
Pack islands — after any unwrap, pack to fill UV space. In pure
--backgroundusepack_islands_bmesh()(operator-free); only usebpy.ops.uv.pack_islandsif a screen exists. Compute margin from texture resolution:margin = px_gap / texture_px(4 px at 2048 = 0.002).CONCAVE/CONVEXdensity is operator-only; the bmesh packer is AABB shelf. Full packing options + bmesh packer:references/seams-packing.md §3(operator) /§7(bmesh). -
Normalize texel density — compute TD per object, scale UVs to match the target from FORGE.md. In pure
--backgroundusenormalize_texel_density_bmesh()(operator-free), then re-pack. Hero props: 1024–2048 px/m. Game environment: 512–1024. Background: 256–512. Full TD formulas + bmesh scaler:references/texel-density.md §4. -
UDIM layout (if needed) — if
FORGE.mdspecifies UDIM workflow or target is Film/VFX: distribute islands to integer tiles (1001, 1002…). Full UDIM setup:references/udim.md. -
Validate — run the UV QA suite:
- Overlap check → must return 0 faces for bake channel. In pure
--backgroundusedetect_overlaps_bmesh()(operator-free);bpy.ops.uv.select_overlaponly if a screen exists. - Out-of-bounds check (UVs outside 0–1 range, unless UDIM).
- TD deviation < 20% from target.
- Utilization > 75% (environment props) / > 85% (hero assets).
Full QA checklist:
references/validation.md.
- Overlap check → must return 0 faces for bake channel. In pure
-
Checker-map render — apply
UV_GRIDorCOLOR_GRIDchecker material, render headlessly to PNG via Cycles CPU. Then callReadon the PNG to visually inspect:- Squares uniform in size (consistent TD) and square-shaped (no stretch).
- No abrupt size jumps at polygon seams.
- No unexpected overlap patterns.
Render command + visual read-back:
references/validation.md §Checker-map render.
-
Export UV layout PNG — for hand-painting or reference. Requires the
io_mesh_uv_layoutaddon (not enabled by default headless) AND an EDIT-mode area, so this is the one step that needs a screen. In pure--backgroundskip it and rely on the checker-map render (step 10). Full export snippet:references/validation.md §UV layout export. -
Write results — report TD, utilization %, overlap count, and PNG path back to the caller (agent or pipeline). If overlaps > 0 for a bake channel: block and fix before handing off to forge-texture. For final gate, call
Skill("forge-validate").- If this asset ships to the web, the chain after texturing/validation is
Skill("forge-export")→Skill("forge-optimize")→Skill("atelier-webgl").
- If this asset ships to the web, the chain after texturing/validation is
Headless invocation pattern
All UV scripts run via:
blender --background <scene.blend> --python <uv_script.py> --python-exit-code 1 -- <args>
- The
--separator is mandatory for passing script arguments. --python-exit-code 1makes Python exceptions fail the process (check$LASTEXITCODE).- Use absolute forward-slash paths in
filepathparameters — Blender's Python prefers POSIX paths even on Windows:"C:/assets/prop.blend"not"C:\\assets\\prop.blend". blender.exe(full path if not on$env:PATH):"C:\Program Files\Blender Foundation\Blender 4.5\blender.exe".
Pure --background is the default — use bmesh, not operators, for post-process ops. The
unwrap/projection solvers (bpy.ops.uv.unwrap, smart_project, cube/cylinder) run headless fine.
But the post-process operators pack_islands / select_overlap / transform.resize require a UV
editor area and fail in pure --background with RuntimeError: poll() failed. Forge runs them via
operator-free bmesh equivalents — no area, no temp_override:
# Pure --background (no screen): the canonical Forge path.
pack_islands_bmesh(obj, margin=0.005) # seams-packing.md §7
assert detect_overlaps_bmesh(obj) == 0 # seams-packing.md §8 — bake channel gate
normalize_texel_density_bmesh(obj, target_td, texture_px) # texel-density.md §4
Only if Blender was launched WITH a screen (GUI / offscreen window) may you instead use the
operator + temp_override path. The export_layout reference PNG is the one step that needs an
area — when there is no screen, skip it and rely on the checker-map render (validation.md §2).
| Step | Pure --background path |
|---|---|
| Pack islands | pack_islands_bmesh() (NOT bpy.ops.uv.pack_islands) |
| Overlap check | detect_overlaps_bmesh() (NOT bpy.ops.uv.select_overlap) |
| TD scale | normalize_texel_density_bmesh() (NOT bpy.ops.transform.resize) |
| Layout PNG | needs a screen → else use checker render |
Full implementations + the area-vs-background matrix: references/unwrap-methods.md §3,
references/seams-packing.md §7/§8, references/texel-density.md §4.
Reference files (read on demand)
| File | Contents |
|---|---|
references/unwrap-methods.md | All unwrap API signatures, gotcha table, headless context override |
references/seams-packing.md | Seam placement rules, island packing options, overlap rules table |
references/texel-density.md | TD formula, TD budget table, batch normalization, per-LOD targets |
references/udim.md | UDIM numbering formula, tile setup, island distribution, UDIM export |
references/validation.md | Full QA suite, checker-map render, UV layout export, overlap detection, determinism checklist |
references/preflight.md | Scale check, UV layer normalization, modifier-stack gotchas |
references/xatlas-fallback.md | No-Blender fallback: xatlas non-overlapping bake-channel UVs + trimesh/PIL QA |
Operating principles
- Apply scale before anything. Unapplied scale corrupts every TD calculation and every
overlap check. If
obj.scale != (1, 1, 1), stop and calltransform_apply(scale=True)first. - Bake channel must be zero overlaps — no exceptions. Overlapping UVs cause light/shadow bleeding. Block the pipeline and report before handing off to forge-texture.
- Checker render is the eyes. After every pack, render the checker map and call
Readon the PNG. Numbers alone cannot catch seam-direction errors or invisible stretching. - Enable
io_mesh_uv_layoutexplicitly. Blender does not auto-enable addons headless. Addaddon_utils.enable("io_mesh_uv_layout", default_set=True, persistent=True)at script start. - Run = call the Skill tool. Handing off to forge-texture, forge-validate, or forge-render
means calling
Skill("forge-texture")/Skill("forge-validate")/Skill("forge-render"). Writing "now run forge-texture" in prose runs nothing.
What ships with it: 7 files
82.7 KB alongside SKILL.md
references/
- preflight.md8.9 KB
- seams-packing.md19.0 KB
- texel-density.md10.7 KB
- udim.md9.2 KB
- unwrap-methods.md13.2 KB
- validation.md15.9 KB
- xatlas-fallback.md5.9 KB