Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
"examples/grease-pencil-rosette",
"examples/image-pixels-testcard",
"examples/light-link-studio",
"examples/lightmap-uv-channel",
"examples/lod-decimate-chain",
"examples/mesh-hygiene-audit",
"examples/modular-kit-snap",
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/blender-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -579,3 +579,17 @@ jobs:
# origins). Exits non-zero on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/modular-kit-snap/modular_kit_snap.py --

- name: Shipped example - lightmap UV channel (two-layer bake contract)
run: |
set -euo pipefail
# Check only (no render): a 9-part market cart; asserts per-part
# UVMap/UVLight layers with active == UVLight and
# active_render == UVMap re-asserted after the ops (they clear
# both flags), UV0 loops untouched by the UV1 unwrap (drift 0),
# every UV1 loop inside [0,1], zero overlapping islands via an
# independent binned SAT scan, measured min island distance >=
# half the nominal pack margin, and watertight parts. Exits
# non-zero on failure.
xvfb-run -a "$BLENDER" --background \
--python examples/lightmap-uv-channel/lightmap_uv_channel.py --
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</p>

<p align="center">
<strong>12 skills</strong> &nbsp;&bull;&nbsp; <strong>6 rules</strong> &nbsp;&bull;&nbsp; <strong>2 templates</strong> &nbsp;&bull;&nbsp; <strong>17 snippets</strong> &nbsp;&bull;&nbsp; <strong>41 examples</strong>
<strong>12 skills</strong> &nbsp;&bull;&nbsp; <strong>6 rules</strong> &nbsp;&bull;&nbsp; <strong>2 templates</strong> &nbsp;&bull;&nbsp; <strong>17 snippets</strong> &nbsp;&bull;&nbsp; <strong>42 examples</strong>
</p>

<p align="center">
Expand Down Expand Up @@ -800,6 +800,26 @@ measured error printed. Companion to
[`prop-origin-transform`](examples/prop-origin-transform/) (pivot discipline)
and [`mesh-hygiene-audit`](examples/mesh-hygiene-audit/) (topology gates).

</td>
</tr>
<tr>
<td width="46%" valign="middle">
<a href="examples/lightmap-uv-channel/"><img src="examples/lightmap-uv-channel/preview.webp" alt="Lightmap UV channel: a wooden market cart with a cream canvas canopy beside a dark atlas board glowing with the bed's packed lightmap islands — proof the second UV layer packs with no overlaps, channel zero untouched" /></a>
</td>
<td valign="middle">

### [lightmap-uv-channel](examples/lightmap-uv-channel/)

The second UV layer engines need for baked lighting, on a reusable market
cart. Per-part `UVMap`/`UVLight` with **`active` vs `active_render` pinned**
(the edit-mode UV ops clear both flags — re-assert or lose them), channel
zero untouched by the second unwrap (drift **0.0**, the clobber probe
measures **2.068**), every island inside [0,1], **0** overlapping islands
by an independent SAT scan, and a measured min island distance of
**0.00401** against the stated margin. Companion to
[`uv-layer-grid`](examples/uv-layer-grid/) (UV authoring) and
[`triangulate-tangents`](examples/triangulate-tangents/) (tangents from UVs).

</td>
</tr>
</table>
Expand Down
5 changes: 3 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,12 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
- ~~LOD decimate chain witness~~ **SHIPPED** as `examples/lod-decimate-chain/` — Decimate COLLAPSE evaluated through the depsgraph is non-destructive (obj.data keeps closed-form counts), evaluated tris hit `ratio × base` within 5% (measured 0.0–0.44%), silhouette bbox survives within 1e-3 (measured 7.7e-6); a stacked Decimate halves the effective ratio, an aggressive 0.02 ratio collapses the nose tip — both caught failure modes
- ~~Vertex weight limit witness~~ **SHIPPED** as `examples/vertex-weight-limit/` — the 4-influence engine cap enforced via the data API (`v.groups` + `VertexGroup.remove` + renormalize); unit sums (measured 3e-8), pose preserved (4.9e-3), exact LBS from the mesh's own deform layer (2.7e-7), Root mount pinned
- ~~Triangulate + tangent-space witness~~ **SHIPPED** as `examples/triangulate-tangents/` — `calc_tangents` aborts on any ngon (back cap must be an explicit fan); mikktspace matches the edge/UV-delta formula within welding tolerance on smooth fields (2.3e-6 measured); planar UVs on a cylindrical wall collapse tangents onto normals (dot 0.998); `MeshUVLoopLayer` handle dangles across `calc_tangents()` on 4.5 (471 phantom flips, silent exit 0) while the mikktspace math is byte-identical on 4.5.11 and 5.1.2
- UV-handle lifetime snippet: re-fetch attribute/UV layers by name after any CustomData-reallocating call (`calc_tangents`, `VertexGroup.add`, modifier edits) — held handles dangle silently on 4.5, survive by luck on 5.1 (found authoring `triangulate-tangents`)
- UV-handle lifetime snippet: re-fetch attribute/UV layers by name after any CustomData-reallocating call (`calc_tangents`, `VertexGroup.add`, modifier edits) — held handles dangle silently on 4.5, survive by luck on 5.1 (found authoring `triangulate-tangents`; **confirmed harder authoring `lightmap-uv-channel`: iterating a held `MeshUVLoopLayer.data` after edit-mode UV ops segfaults 4.5.11 headless, EXCEPTION_ACCESS_VIOLATION 5/5, survives on 5.1.2**)
- ~~glTF skinned-mesh export witness: follow-up to `gltf-export-roundtrip` + `vertex-weight-limit`~~ **SHIPPED** as `examples/gltf-skin-roundtrip/` — `skins[0].joints` names every bone, JOINTS_0/WEIGHTS_0 with unit sums (3e-8), weights bit-exact, rest matrices to 2.4e-07, deformation to 4.8e-07; exporter welds duplicate loops (sorted-multiset comparisons mispair — compare by rest-key); unparented skinned meshes make the exporter bind an armature by name
- ~~Degenerate-bevel weld hazard~~ **SHIPPED** as `examples/degenerate-bevel-weld/` — at `offset == min_dim/2` the bevel band collapses to exactly 12 zero-area faces (4 min-axis edges × 3 segments) with 16 coincident verts (4 × (segments+1)) and min_area down 3.2e5×; a stdlib GLB re-parse counts **32 degenerate triangles crossing the export boundary** (MEASURED regression constant) versus 0 for the safe mesh — the loops an engine merge-by-distance welds; byte-identical on 4.5.11 and 5.1.2
- ~~Modular kit snap witness~~ **SHIPPED** as `examples/modular-kit-snap/` — tiling corridor segment: 16 boundary verts on `x ∈ {0, TILE}` within 1e-6 m, end rings coincident under the tile offset (nearest-key match), linked-duplicate joint deviation 0.0, shell bbox == declared tile (dev 0.0), manifold except the 16 open-end edges, 12 detail parts contained inside the tile; unsnapped probe (3 mm skew, 2 mm nudge) fails at exits 3/4 with measured errors; sorted-zip ring matching mispairs displaced verts — match by nearest key (authoring hazard, fixed); byte-identical on 4.5.11 and 5.1.2
- ~~Lightmap UV channel witness~~ **SHIPPED** as `examples/lightmap-uv-channel/` — two-channel UV contract on a market cart: per-part `UVMap`/`UVLight` with `active`/`active_render` re-asserted after the ops (edit-mode UV ops clear both flags; `uv_layers.new()` never moves them), UV0 drift 0.0 (clobber trap measured 2.068), every UV1 loop in [0,1], 0 overlapping islands via independent binned strict-SAT (15 hits when falsified), min island distance 0.00401 vs nominal margin 0.002 (`MARGIN_DIV × 0.01` semantics measured live); held `MeshUVLoopLayer.data` after edit-mode UV ops segfaults 4.5.11 (5/5, EXCEPTION_ACCESS_VIOLATION), silent no-op pack without prior unwrap; byte-identical on 4.5.11 and 5.1.2 (1114 islands)
- UV atlas **utilization** witness — coverage/wasted-texel closed forms for a packed lightmap atlas (the non-overlap, unit-square, margin, and active/active_render contracts shipped in `lightmap-uv-channel`; utilization is the remaining unbuilt slice of the old "UV atlas pack" candidate)
- ~~GAMMA_CROSS blend-curve witness~~ **SHIPPED** as `examples/vse-gamma-cross/` — the cross blends in a gamma-0.5 space: `((1-t)·√A + t·√B)²` with `t = (frame − start)/duration`, never 1 inside the effect; mid-cross dips 0.115 below the sRGB lerp from crimson/teal (closed form (0.341, 0.349, 0.463) confirmed per frame); AgX-default sampling poisons the fit (0.146 red-channel error, `view_transform='Standard'` mandatory); deleting a consumed input orphans-and-deletes the effect — follow-up to `vse-cut-list`
- Falsy `bpy_prop_collection` trap snippet: an empty collection is falsy, so `editor.strips or editor.sequences` silently falls through to the legacy accessor on an empty timeline — always branch on `hasattr`; likely generalizes across the API (found authoring `vse-cut-list`)
- ~~Collision compound witness~~ **SHIPPED** as `examples/collision-hull-proxy/` — game-prop collision as a compound of convex pieces, each a `bmesh.ops.convex_hull` of a coarse `sec(π/n)`-inflated cage (containment 4.4e-08, watertight, positive signed volume, Euler 2, per-piece 255-face budget: body 70, caps 60×3, compound 250); a hull of the dense render mesh measures 380 faces — over budget — which is why pipelines hull cages; proud details cost cage rows, concave grooves are free; byte-identical on 4.5.11 and 5.1.2
Expand All @@ -126,7 +128,6 @@ Not committed; target list for the next content version. (v0.3.0 shipped the smo
- Dice-pair per-face witness: material/attribute assignment driven by face normal direction, opposite-faces-sum-to-7 as an independently computed invariant, pip placement from a closed-form lattice
- Bicycle-wheel radial witness: spokes via radial Array with object offset — exact angular spacing, spoke count, hub/rim concentricity, every evaluated spoke endpoint on its computed rim coordinate
- ~~mesh-hygiene-audit witness~~ **SHIPPED** as `examples/mesh-hygiene-audit/` — engine-ingest topology checklist on a stepped street electrical pedestal: no ngons, no loose verts, manifold edges (exactly 2 faces), no zero-area faces (`min_area` printed), positive signed volume, Euler `V−E+F==2` (24/44/22, volume 0.989248); byte-identical on 4.5.11 and 5.1.2; dual-panel dirty vs clean still
- UV atlas pack witness — lightmap/unique UV island packing with non-overlap + utilization closed forms (deferred behind hygiene/origin; overlaps `uv-layer-grid` / `triangulate-tangents` / `gltf-export-roundtrip` UV arc)

- ~~Gallery framing recomposition worklist~~ **DRAINED**: all four recomposition cases restaged and gated with `check_framing` — depsgraph-export (0.984x/touch→0.812x; cube+dome recentered, aim-based camera), vertex-weight-limit (touch B→0.867y; more frontal camera, lower aim, base in frame), triangulate-tangents (0.334x→0.833y; 2x-class move-in plus Key/Glint trim that also cleared a pre-existing dome blowout), text-version-stamp (0.663x→0.719x; moved in with aim on the stamp center, dead third gone). The seven marginal cases were camera-nudged in the preceding sweep; deviations documented in #108 (damped-track-aim, wave-displace); sky-texture-sun-elevation is a measurement artifact (world subject — report-only if wired). Remaining: nothing on the framing worklist — future examples inherit the gate at authoring time.

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 12 additions & 1 deletion docs/gallery/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ <h1>Examples Gallery</h1>
autocomplete="off" spellcheck="false" aria-label="Search examples" />
<button class="q-clear" id="qClear" type="button" aria-label="Clear search" hidden>&times;</button>
</div>
<span class="count" id="count" role="status" aria-live="polite">41 examples</span>
<span class="count" id="count" role="status" aria-live="polite">42 examples</span>
<div class="density" role="group" aria-label="Card density">
<button class="density-btn" data-density="compact" type="button" aria-pressed="false">Compact</button>
<button class="density-btn" data-density="detailed" type="button" aria-pressed="false">Detailed</button>
Expand Down Expand Up @@ -773,6 +773,17 @@ <h2><a href="modular-kit-snap/">modular-kit-snap</a></h2>
<a class="card-link" href="modular-kit-snap/">View example <span aria-hidden="true">&rarr;</span></a>
</div>
</article>
<article class="card" data-tags="uv game-pipeline render">
<a class="card-media" href="lightmap-uv-channel/" aria-label="lightmap-uv-channel example detail page">
<img src="assets/lightmap-uv-channel-hero.webp" alt="lightmap-uv-channel — A market cart carrying the two-channel UV contract for baked lighting: UV0 untouched, UVLight packed with no overlaps and a respected margin." loading="lazy" decoding="async" />
</a>
<div class="card-body">
<h2><a href="lightmap-uv-channel/">lightmap-uv-channel</a></h2>
<p class="teaches">A market cart carrying the two-channel UV contract for baked lighting: UV0 untouched, UVLight packed with no overlaps and a respected margin.</p>
<p class="witnesses"><span class="tag">witnesses</span> Per-part UVMap/UVLight with active vs active_render pinned (ops clear both flags), UV0 drift 0.0, 1114 islands with 0 SAT overlaps, min island distance 0.00401.</p>
<a class="card-link" href="lightmap-uv-channel/">View example <span aria-hidden="true">&rarr;</span></a>
</div>
</article>
</div>
<p class="noresults" id="noResults" hidden>No examples match the current filters.
<button class="chip" id="resetFilters" type="button">Clear search and tags</button></p>
Expand Down
Loading
Loading