@bitmagic/cli 0.1.66-dev.5 → 0.1.66-dev.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +36 -1
  2. package/assets/character-skin-authoring/SKILL.md +43 -0
  3. package/assets/character-skin-authoring/references/exporters.md +134 -0
  4. package/assets/character-skin-authoring/references/eyes.md +215 -0
  5. package/assets/character-skin-authoring/references/materials.md +115 -0
  6. package/assets/character-skin-authoring/references/playground.md +78 -0
  7. package/assets/character-skin-authoring/references/profiles.md +97 -0
  8. package/assets/character-skin-authoring/references/projection.md +190 -0
  9. package/assets/character-skin-authoring/references/regional-detail.md +72 -0
  10. package/assets/character-skin-authoring/scripts/assemble_character.py +205 -0
  11. package/assets/character-skin-authoring/scripts/authored_detail.py +47 -0
  12. package/assets/character-skin-authoring/scripts/authored_surface_patch.py +83 -0
  13. package/assets/character-skin-authoring/scripts/brow_groom.py +62 -0
  14. package/assets/character-skin-authoring/scripts/build_face_detail.py +107 -0
  15. package/assets/character-skin-authoring/scripts/build_surface_candidate.py +28 -0
  16. package/assets/character-skin-authoring/scripts/canthus_wall.py +57 -0
  17. package/assets/character-skin-authoring/scripts/character_build.py +54 -0
  18. package/assets/character-skin-authoring/scripts/eye_assets.py +333 -0
  19. package/assets/character-skin-authoring/scripts/eye_opening.py +114 -0
  20. package/assets/character-skin-authoring/scripts/eye_texture.py +35 -0
  21. package/assets/character-skin-authoring/scripts/eyelid_detail.py +34 -0
  22. package/assets/character-skin-authoring/scripts/eyelid_morph.py +171 -0
  23. package/assets/character-skin-authoring/scripts/eyelid_patch.py +173 -0
  24. package/assets/character-skin-authoring/scripts/face_atlas.py +51 -0
  25. package/assets/character-skin-authoring/scripts/geometry_repair.py +112 -0
  26. package/assets/character-skin-authoring/scripts/glb_arrays.py +13 -0
  27. package/assets/character-skin-authoring/scripts/glb_output.py +21 -0
  28. package/assets/character-skin-authoring/scripts/inspect_skin_point.py +66 -0
  29. package/assets/character-skin-authoring/scripts/normal_patch_height.py +38 -0
  30. package/assets/character-skin-authoring/scripts/prepare_face_reference.py +23 -0
  31. package/assets/character-skin-authoring/scripts/regional_atlas.py +51 -0
  32. package/assets/character-skin-authoring/scripts/select_preview.py +90 -0
  33. package/assets/character-skin-authoring/scripts/skin_views.py +267 -0
  34. package/assets/character-skin-authoring/scripts/surface_pbr_maps.py +46 -0
  35. package/assets/character-skin-authoring/scripts/texture_repair.py +98 -0
  36. package/assets/character-skin-authoring/scripts/vertex_detail_support.py +80 -0
  37. package/assets/character-skin-authoring/scripts/vision_blend_materials.py +74 -0
  38. package/assets/character-skin-authoring/scripts/vision_materials.py +276 -0
  39. package/assets/character-skin-authoring/scripts/workspace_paths.py +18 -0
  40. package/assets/metahuman/src/work/metahuman/MetaHumanActor.ts +580 -0
  41. package/assets/metahuman/src/work/metahuman/MetaHumanLabHooks.ts +122 -0
  42. package/assets/metahuman/src/work/metahuman/MetaHumanMaterials.ts +500 -0
  43. package/assets/metahuman/src/work/metahuman/MetaHumanSpeech.ts +242 -0
  44. package/assets/metahuman/src/work/metahuman/StudioEnvironment.ts +142 -0
  45. package/assets/metahuman/tools/lipsync/make_line.py +181 -0
  46. package/assets/metahuman/tools/metahuman/README.md +21 -0
  47. package/assets/metahuman/tools/metahuman/e2e/eval.mjs +34 -0
  48. package/assets/metahuman/tools/metahuman/e2e/probes/arm-pose-check.js +32 -0
  49. package/assets/metahuman/tools/metahuman/e2e/probes/bone-displacement.js +26 -0
  50. package/assets/metahuman/tools/metahuman/e2e/probes/clip-shoulder.js +41 -0
  51. package/assets/metahuman/tools/metahuman/e2e/probes/grafted-bones.js +11 -0
  52. package/assets/metahuman/tools/metahuman/e2e/probes/helper-follow-descent.js +38 -0
  53. package/assets/metahuman/tools/metahuman/e2e/probes/helper-follow-sweep.js +31 -0
  54. package/assets/metahuman/tools/metahuman/e2e/probes/helper-joints-inspect.js +10 -0
  55. package/assets/metahuman/tools/metahuman/e2e/probes/outfit-bad-vertices.js +26 -0
  56. package/assets/metahuman/tools/metahuman/e2e/probes/outfit-body-material.js +7 -0
  57. package/assets/metahuman/tools/metahuman/e2e/probes/outfit-own-skeleton.js +8 -0
  58. package/assets/metahuman/tools/metahuman/e2e/probes/shirt-bone-ownership.js +25 -0
  59. package/assets/metahuman/tools/metahuman/e2e/probes/shirt-edge-stretch.js +26 -0
  60. package/assets/metahuman/tools/metahuman/e2e/probes/shirt-long-edges.js +23 -0
  61. package/assets/metahuman/tools/metahuman/e2e/probes/walk-sampler.js +105 -0
  62. package/assets/metahuman/tools/metahuman/e2e/shot.mjs +125 -0
  63. package/assets/metahuman/tools/metahuman/e2e/walk-probe.mjs +43 -0
  64. package/assets/metahuman/tools/metahuman/merge-skeletons.mjs +69 -0
  65. package/assets/metahuman/tools/metahuman/package.json +13 -0
  66. package/assets/metahuman/tools/metahuman/prepare.sh +25 -0
  67. package/assets/metahuman/tools/metahuman/reorder-body-first.mjs +20 -0
  68. package/assets/metahuman/tools/metahuman/smooth-outfit-weights.mjs +48 -0
  69. package/assets/metahuman/tools/metahuman/strip-draco.mjs +32 -0
  70. package/assets/metahuman/tools/metahuman/transfer-skin-weights.mjs +90 -0
  71. package/dist/commands/generate.d.ts +49 -0
  72. package/dist/commands/generate.js +168 -1
  73. package/dist/commands/generate.js.map +1 -1
  74. package/dist/generate/audio-file.d.ts +6 -0
  75. package/dist/generate/audio-file.js +42 -0
  76. package/dist/generate/audio-file.js.map +1 -0
  77. package/dist/generate/music.d.ts +4 -3
  78. package/dist/generate/music.js +6 -23
  79. package/dist/generate/music.js.map +1 -1
  80. package/dist/generate/stream.d.ts +13 -0
  81. package/dist/generate/stream.js +14 -1
  82. package/dist/generate/stream.js.map +1 -1
  83. package/dist/scaffold/asset-pipeline-skill-files.js +2 -0
  84. package/dist/scaffold/asset-pipeline-skill-files.js.map +1 -1
  85. package/dist/scaffold/character-skin-skill-files.d.ts +2 -0
  86. package/dist/scaffold/character-skin-skill-files.js +49 -0
  87. package/dist/scaffold/character-skin-skill-files.js.map +1 -0
  88. package/dist/scaffold/metahuman-skill-files.d.ts +21 -0
  89. package/dist/scaffold/metahuman-skill-files.js +306 -0
  90. package/dist/scaffold/metahuman-skill-files.js.map +1 -0
  91. package/dist/scaffold/project-files.js +4 -4
  92. package/dist/scaffold/project-files.js.map +1 -1
  93. package/dist/scaffold/project.js +4 -0
  94. package/dist/scaffold/project.js.map +1 -1
  95. package/dist/scaffold/skill-files.js +3 -1
  96. package/dist/scaffold/skill-files.js.map +1 -1
  97. package/dist/tools/bundles.js +8 -0
  98. package/dist/tools/bundles.js.map +1 -1
  99. package/package.json +4 -4
package/README.md CHANGED
@@ -217,7 +217,7 @@ browser reloads itself on every change and the assets panel shows each generatio
217
217
  | `bitmagic trailer publish <file.mp4> [--no-attach]` | Upload a trailer (`.mp4`/`.webm`, ≤ 200 MiB, header-checked so a renamed image is refused before upload) to the CDN under `game-media/<gameId>/` and put it at the front of the game page gallery. Re-running replaces the previous trailer (remembered in `.bitmagic/trailer/published.json`); the page is capped at 12 media items. Works before the first publish — the page goes live on the first `bitmagic publish --visibility public`. `--no-attach` uploads only. |
218
218
  | `bitmagic forge --prompt "..." [--city\|--dungeon\|--platformer\|--freeform] [--name <name>] [--resume <jobId>]` | Design and bake a whole playable level into `world.json`. Costs sparks, and takes many minutes — the bake alone can take twenty. `--resume <jobId>` picks a failed run back up from the last step that finished, rather than redoing the whole thing. |
219
219
  | `bitmagic forge --edit "..." [--level <id or name>]` | Change a detail of a level this project forged — a door style, the light fixtures, a prop — without re-forging it. The stored design is patched and only what the change touches is re-made; the level is replaced in place. See [Editing a forged level](#editing-a-forged-level). |
220
- | `bitmagic tools <list\|path\|install> [bundle]` | The script bundles the CLI ships for skills that drive Blender or Python (`blender-level`, `unity-import`): what they are, where this install keeps them, and `install` to copy one into the project's `tools/`. Local, no network, no sparks. |
220
+ | `bitmagic tools <list\|path\|install> [bundle]` | The script bundles the CLI ships for skills that drive Blender, Python or Node (`blender-level`, `unity-import`, `metahuman`): what they are, where this install keeps them, and `install` to copy one into the project's `tools/`. Local, no network, no sparks. |
221
221
  | `bitmagic levels <list\|add\|rename\|set-start\|remove> ...` | Manage the levels `forge` creates: which one boots, their names, registering a bake you already have, deleting one. Local, no network, no sparks. See **Managing levels** below. |
222
222
 
223
223
  Every command exits non-zero on failure with a single-line message (no stack trace) and, where a
@@ -531,6 +531,32 @@ before. Without a prior user gesture the browser blocks autoplay, and the engine
531
531
  immediately — so the cutscene silently does not run. `engine/agent-docs/video-cutscenes.md` covers
532
532
  that and what to freeze while a cutscene plays.
533
533
 
534
+ ## Spoken lines
535
+
536
+ `bitmagic generate speech --text "Halt, traveler. You shall not pass."` speaks a line, writes it
537
+ into `world.json` as an audio asset, and prints the `engine.playSound("<id>")` call that plays it.
538
+ Unlike a music bed it is registered as a **one-shot, not a loop** — dialogue plays when something
539
+ triggers it.
540
+
541
+ `--voice` picks who says it: `narrator` (the default), `male`, `female`, or a raw Eleven Labs
542
+ `voice_id` if you have cloned one of your own. `--model` switches model, and `--stability`,
543
+ `--similarity-boost`, `--style` and `--speed` are passed through to Eleven Labs when you want them;
544
+ leave them alone and Eleven Labs' own defaults apply.
545
+
546
+ It is **billed per second of audio produced**, not per character of text. A sentence costs about a
547
+ spark. The estimate charged up front comes from the length of the text; what you actually pay comes
548
+ from the finished audio.
549
+
550
+ Like `generate music`, it can write a file instead of a game asset:
551
+
552
+ ```bash
553
+ bitmagic generate speech --text "Halt, traveler." --out line.mp3 --no-world
554
+ ```
555
+
556
+ `--out` saves the MP3, `--no-world` leaves `world.json` untouched. That pair is the input to the
557
+ MetaHuman lip-sync tool (`tools/lipsync/make_line.py --audio line.mp3`), where a spoken line is
558
+ cut into mouth cues rather than played as-is. Use `--out` on its own to keep both.
559
+
534
560
  ## Reference image
535
561
 
536
562
  When a game has a strong setting — a tropical island, a neon city — one accepted concept image can
@@ -1306,6 +1332,15 @@ by the engine's `MeshLevel`. The scaffolded `building-levels-in-blender` skill w
1306
1332
  its first section says when that path applies (a frontier model, and Blender installed) and sends
1307
1333
  everything else to `bitmagic forge`.
1308
1334
 
1335
+ ## Importing a MetaHuman
1336
+
1337
+ An Epic MetaHuman (a UE 5.7 glTF export from the smorchj/metahuman-to-glb pipeline) can be the
1338
+ game's playable high-res character without voxelization. The scaffolded `importing-metahumans` skill
1339
+ carries the whole path — `bitmagic tools install metahuman` lands the GLB preparation scripts, the
1340
+ runtime module (`src/work/metahuman/`), the lip-sync tool and a headless verification rig — and names
1341
+ each failure a raw export produces (arms crossed into the chest, a torn shirt, hair left behind by a
1342
+ head turn, tinted skin, black eyes) with the fix that resolved it.
1343
+
1309
1344
  ## Art style
1310
1345
 
1311
1346
  A 3D game is voxel-built unless `src/work/game.json` says otherwise:
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: character-skin-authoring
3
+ description: Use vision to author and review exposed-skin maps on textured 3D characters, including faces, hands and bodies. Prepare exact model views, annotate visible anatomy, project evidence into UV space, and review skin detail placement. Eye construction is a separate workflow.
4
+ ---
5
+
6
+ # Vision-led character skin authoring
7
+
8
+ The local agent makes anatomical/material decisions from images. Do not replace those decisions with RGB thresholds, world-height cutoffs, race/name rules, or another automated classifier. Deterministic tools handle projection and bookkeeping. The creator's existing agent subscription supplies vision; this workflow requires no hosted segmentation service.
9
+
10
+ ## Establish evidence
11
+
12
+ Locate the model, its physical height, materials, texture resolution and rig. Keep the original immutable and write a separate material revision. Inspect the original generated image when available, but make the **actual mesh and its textures** authoritative: the generated mesh may differ from that image.
13
+
14
+ Use the local `scripts/skin_views.py` helper to create unlit, occlusion-correct views with their UV correspondences. Read [the projection contract](references/projection.md) for commands and formats. It requires local Blender and a Python environment with NumPy/Pillow. The helper performs no semantic recognition. Verify orientation from the resulting images; its axes are not anatomical labels.
15
+
16
+ Start with a full-body survey from opposite directions. Then frame each exposed region closely enough to see its boundaries. Inspect the face from front and both sides; inspect both hands from palm and dorsal sides and oblique angles showing finger webs. Inspect ears, neck, chest, arms, legs, feet or any other exposed region actually present. Add cameras when existing views cannot show a surface. Do not infer a hidden palm from a dorsal hand image or project a front silhouette through to the back.
17
+
18
+ ## Author the maps using vision
19
+
20
+ For each viewed surface, annotate pixel polygons as `skin`, `dorsal_hand`, `palm`, `sole`, `lips`, `eyes`, `hair`, `nails`, or `non_skin`. `unknown` is explicit unresolved evidence. Use separate polygons for exclusions, ordered after enclosing polygons. Do not give an indistinct nail facial pores merely because the rest of the hand is clear. Record why a boundary is ambiguous; obtain a closer/different view before resolving it. Scars, freckles, tattoos and makeup usually remain skin with appearance annotations, not separate non-skin regions. Tight cloth is still cloth; green skin is still skin. If garment colour spills onto anatomically visible skin in the source albedo, record a texture defect separately from the semantic mask. A correct skin label cannot repair that colour.
21
+
22
+ Review the colored annotation overlay on the **same source image**, then review the **baked atlas reprojected onto every prepared view**, including unannotated side views. Use the dense visibility bake at a resolution appropriate to the source atlas; sparse splatting is a diagnostic, not a finished mask. Include the filename, image dimensions and source hash with every annotation set. If a tool displays a resized image, convert coordinates back to the recorded dimensions. Never claim to have visually reviewed an image you have not opened.
23
+
24
+ The helper deliberately leaves unobserved UV texels unknown and reports contradictory labels. Do not grow a skin mask across unknown areas to make a coverage statistic look good. Get additional views, increase sampling resolution, or use a reviewed Blender texture-paint correction. Mirrored/overlapping UVs can make conflicting anatomical labels impossible in one atlas: document that and create separate material/UV regions rather than average the labels.
25
+
26
+ ## Apply region-appropriate detail
27
+
28
+ For material application and engine integration, read [material application](references/materials.md). The [installed exporters](references/exporters.md) assemble reviewed inputs in an explicit external workspace. After coverage passes review, register landmarks and surface scale for each detail patch. Use licensed exemplars and retain attribution and modification provenance. The b3662 face pilot in this repository demonstrates registered scan detail; its coordinates are **not** a universal face template.
29
+
30
+ - Face: region-specific pores, fine relief, oiliness and pigment. Exclude eye surfaces, lashes, brows, lips and facial hair from the ordinary pore layer; preserve actual folds and identity.
31
+ - Dorsal hands/fingers: knuckle folds, tendons and finer hand texture. Nails receive their own response.
32
+ - Palms/soles: glabrous skin with appropriate creases/ridges and roughness; do not stamp facial follicles onto it.
33
+ - Neck, torso, limbs, ears: use suitable regional detail and scale. Preserve the character's natural variation; do not transplant a donor's beard, identity marks or complexion.
34
+
35
+ Blend patch boundaries in surface space and check physical scale. A silhouette or clothing boundary needs a coverage edge; two adjacent skin patches need a continuous transition. Keep skin nonmetallic and preserve clothing/armor materials. Use the existing registered detail/SSS renderer where available; do not invent new renderer hooks or claim the projection helper installs materials by itself.
36
+
37
+ ## Review and handoff
38
+
39
+ Inspect colored material regions and final shaded results separately. Use fixed cameras under diffuse, specular, side, studio and back lighting. Check full-body, face-sized and close detail views, plus a representative pose when the model is rigged. Confirm both hands, finger webs, nails, ears and every other exposed area; inspect clothing edges without revisiting unrelated deferred edits.
40
+
41
+ Record results per character and region: `reviewed`, `needs_view`, `conflict`, or `needs_detail_asset`. Archive source hashes, views, annotations, projected labels, atlas registration, licenses and review images together. Only call a character complete when its exposed regions are reviewed and the **applied** maps have been inspected. A parseable annotation file or a successful bake is not semantic validation.
42
+
43
+ Review the face and ocular exclusion before eye geometry/shading work; use the separate [optical-eye workflow](references/eyes.md) when that work is requested. Eye progress does not mark unresolved body skin as complete. This workflow is maintained in the GDK CLI assets and installed into supported agent skill directories from the same source. Keep per-character evidence and candidates outside those refreshed directories.
@@ -0,0 +1,134 @@
1
+ # Installed character exporters
2
+
3
+ The skill now includes the tested offline skin, optical-eye and rig-assembly helpers.
4
+ Run `scripts/character_build.py` with an explicit `--workspace`; character assets live
5
+ outside the skill so refreshes do not erase them. Python needs NumPy, Pillow and SciPy.
6
+ Exact visibility recovery also needs Blender on PATH or `BITMAGIC_BLENDER`. These tools
7
+ perform deterministic assembly of the agent's reviewed inputs, never semantic recognition.
8
+
9
+ The retained workspace convention is:
10
+
11
+ ```text
12
+ characters/ID/high/v1/
13
+ source/hy31pro.glb immutable source (name is a convention)
14
+ output/viewer-profile.json {"height": physical height in metres}
15
+ materials/body-detail-profile.json optional designed regional creases
16
+ materials/surface-patch-profile.json optional licensed regional patches
17
+ materials/repair-profile.json optional separately reviewed source defects
18
+ materials/v2/ registered face inputs and intermediate maps
19
+ materials/v4/ mixed-surface GLB and report
20
+ eyes/v1/ independent fitted optical-eye revision
21
+ output/character.glb optional existing bound body mesh
22
+ rig-report.json optional validated rig provenance
23
+ runtime/v1/ combined surface/eye/body variants
24
+ highquality/materials/faces/ID.json character-specific landmark registration
25
+ highquality/references/ licensed immutable exemplar files
26
+ ```
27
+
28
+ Evidence/masks/eye profiles can be anywhere supplied explicitly. Relative command paths
29
+ are workspace-relative. Keep their source/image hashes and projection receipts intact.
30
+ Paths inside authored JSON retain their documented conventions; relocating evidence may
31
+ require updating its source path without changing source bytes or camera contracts.
32
+
33
+ ## Commands
34
+
35
+ Use [the profile schemas](profiles.md) for independently authored landmarks, exclusions,
36
+ scale and optical dimensions. After preparing the facial profile:
37
+
38
+ ```sh
39
+ python scripts/character_build.py --workspace /path/to/assets --id CHARACTER --stage face
40
+ ```
41
+
42
+ The current face adapter uses the Lee Perry-Smith reference: `LeePerrySmith.glb`,
43
+ `Infinite-Level_02_Disp_NoSmoothUV-4096.jpg` and `Map-COL.jpg` in
44
+ `highquality/references/lee-perry-smith/`. Obtain the licensed originals explicitly and
45
+ retain CC BY 3.0 attribution; the skill does not download them. The adapter writes its
46
+ modification notice and hashes. Its calibrated relief amplitude is an authoring estimate,
47
+ not measured capture scale. It does not transfer donor face geometry.
48
+
49
+ After reviewing the dense semantic bake:
50
+
51
+ ```sh
52
+ python scripts/character_build.py --workspace /path/to/assets --id CHARACTER \
53
+ --evidence evidence/CHARACTER --masks masks/CHARACTER
54
+ ```
55
+
56
+ This preserves source geometry and writes mixed skin/hair/lip/nail materials plus the
57
+ registered detail binding. The adapter currently requires one source mesh primitive,
58
+ embedded textures, normals and non-overlapping anatomical UV ownership. It fails unsupported
59
+ layouts rather than flattening them automatically. Multiple-material adapters remain work.
60
+ `--check` validates required input presence without building; full geometry/hash contracts
61
+ are checked by the exporters themselves. Neither check is visual acceptance.
62
+
63
+ For eyes, first follow [the eye fitting workflow](eyes.md), then:
64
+
65
+ ```sh
66
+ python scripts/character_build.py --workspace /path/to/assets --id CHARACTER \
67
+ --stage eyes --eyes-profile profiles/CHARACTER-eyes.json
68
+ ```
69
+
70
+ The current optical texture adapter uses `blue_eye.png` and `LICENSE.md` from the CC0
71
+ MakeHuman eye reference in `highquality/references/makehuman-eyes/`. Its source registration
72
+ is specific to that donor atlas. Character opening contours, dimensions and fitting remain
73
+ individually authored. Existing skinned cut edges/full facial rigs are not supported by
74
+ this prototype; preserve them and use a suitable topology adapter.
75
+
76
+ For a previously validated body binding:
77
+
78
+ ```sh
79
+ python scripts/character_build.py --workspace /path/to/assets --id CHARACTER \
80
+ --stage assemble --input eyes/v1/character.glb --variant eyes
81
+ ```
82
+
83
+ The assembler consumes the existing bound mesh and `rig-report.json`, verifies the output
84
+ hash and negligible geometry displacement, then retains materials and eye layers while
85
+ adding the body skin. It does not invent bones, fit a skeleton or simulate cloth. The
86
+ playground's shared Blender rig fitting remains separate from this installed exporter.
87
+ Use the project's existing rigging workflow to produce compatible inputs.
88
+
89
+ A surfaces run can also take `--eyes-profile` and `--assemble` to execute the same stages
90
+ in order. Each stage stops on failure and leaves a review candidate, never `viewerReady`.
91
+ Review every changed region and both rendering backends before selecting a local preview.
92
+
93
+ ## Detail-binding seams
94
+
95
+ Unused UV texels are not reliable vertex visibility samples at split seams. The exporter
96
+ uses exact source-geometry rays for those vertices, then samples the same reviewed image
97
+ annotations. It leaves occupied unknown/conflicted samples untouched and never changes
98
+ fragment coverage. Geometric caches include source, cameras, positions, normals and
99
+ algorithm version; annotation labels are re-read. Adjacent zero-weight triangle corners
100
+ still receive coherent patch coordinates so interpolation cannot sample another atlas
101
+ region. If an artifact persists, inspect coverage, geometry normals and source color
102
+ separately before changing skin strength.
103
+
104
+ Eye rest fitting retains `_BIND_SOURCE_POSITION` before moving source eyelid vertices.
105
+ The assembly exporter consumes this authoring attribute for weight correspondence and
106
+ removes it from the runtime attributes. Original vertices use their exact bound match;
107
+ clipped vertices use a verified rigid-head field or closest-triangle barycentric weights.
108
+ Points outside the bound surface tolerance fail rather than inheriting a nearby limb.
109
+ The rendered fitted positions and morphs retain their shape during this transfer.
110
+
111
+ Local preview selection now copies the exact reviewed GLB, render receipt, visual
112
+ verdict and inspected images into a content-addressed `.previews` snapshot beside
113
+ the candidate. An atomic `*.selected.json` pointer names that snapshot. Rebuilding
114
+ the candidate or its review images does not mutate the selected preview. A failed
115
+ review leaves the previous pointer intact. Engine consumers should resolve the
116
+ selected snapshot for ordinary preview and use explicit candidate paths for QA.
117
+ These snapshots remain local previews with recorded issues, not whole-character
118
+ acceptance or a publication step.
119
+
120
+ An explicitly authored `materials/geometry-repair-profile.json` can correct a local
121
+ source defect during the mixed surface build. Select the defect center and clean
122
+ support annulus from the exact evidence view; supply a bounded depth interval and
123
+ maximum displacement. The quadratic patch follows surrounding curvature and feathers
124
+ into unchanged geometry. Never infer that a painted marking should be removed:
125
+ record the user's intent and preserve the source. Optional clean skin color donors
126
+ and a painted dot replace the source's baked bump shading. Evidence UVs use Blender's
127
+ bottom-left convention; decoded texture rows use top-left. The exporter converts
128
+ this explicitly and pads only adjacent unused UV gutters.
129
+
130
+ The repair keeps topology, UVs and `_BIND_SOURCE_POSITION`; subsequent eye fitting
131
+ must preserve that attribute, and assembly uses it for the original rig weights.
132
+ Rebuild both eyes and runtime assemblies after a repair. Inspect front and oblique
133
+ views and both renderer backends before selecting the new snapshots. A displacement
134
+ receipt alone does not prove that old normal-map or pigment shading is gone.
@@ -0,0 +1,215 @@
1
+ # Optical eyes after reviewed ocular exclusions
2
+
3
+ This is an independent, opt-in asset revision. A working eye pilot does not certify the
4
+ skin maps or body rig. Preserve the source, material revision and existing animation.
5
+ The current adapter supports a single, unskinned source mesh and two eyes; it refuses
6
+ existing facial morphs and skinned cut edges. Do not silently flatten a rig to bypass it.
7
+
8
+ ## Availability
9
+
10
+ The [installed exporter runner](exporters.md) now includes the optical-eye builder and
11
+ its dependencies. Supply an explicit workspace and independently authored fit; exemplar
12
+ textures remain external licensed inputs. The playground browser review harness is still
13
+ separate. Confirm the installed engine supports the optical-eye contract before adoption.
14
+
15
+ ## Vision fit
16
+
17
+ Prepare exact close front and both oblique source views with `skin_views.py prepare`.
18
+ Use enough pixels to distinguish the iris, visible eye opening, inner corner and lids.
19
+ Record each iris center/radius, an ordered convex opening contour and the lower contour
20
+ indices on the original image. Record anatomical left/right explicitly; image orientation
21
+ is not a side label. Do not reuse another character's target pixels or eye centers.
22
+
23
+ Write a profile following `highquality/materials/eyes/b3843.json`. Source and evidence
24
+ hashes are mandatory. Globe radius, corneal bulge, pupil ratio, pigment and depth offset
25
+ are authored estimates in metres. Verify those estimates against side views and physical
26
+ character height. An opening wider than the globe requires corner tissue; moving the
27
+ eyeball forward until it fills the hole is not a valid substitute.
28
+
29
+ Run `python highquality/src/eye_assets.py --profile PROFILE`. The builder ray-fits each
30
+ eye against source geometry and writes `characters/ID/high/v1/eyes/v1/`. It clips openings
31
+ at the reviewed contour with barycentric attribute interpolation. It creates separate
32
+ sclera, recessed iris, pupil, cornea, orbital mucosa, lid contact and tear meniscus surfaces.
33
+ It adds actual eyelid position/normal morphs and gaze/blink clips. Inspect the closed lids:
34
+ the builder's deformation is a starting fit, not an anatomically validated universal rig.
35
+
36
+ ## Shared rendering and control contract
37
+
38
+ - Eye nodes have `extras.characterEye=true` and `forwardAxis=+Z`; local +Y is up.
39
+ - `CharacterEyeController` applies local yaw/pitch relative to the authored rest fit and
40
+ drives `eyeBlinkLeft`/`eyeBlinkRight`. It never scales the eyeballs or changes body bones.
41
+ Give these channels one owner: either this controller or an AnimationMixer clip.
42
+ - Corneal transmission/IOR use standard glTF physical-material extensions on both backends.
43
+ Source ocular textures are not a replacement for a clear cornea and recessed iris.
44
+ - The MakeHuman eye source is CC0; retain its license, immutable source hash and adaptation
45
+ record. The current texture uses reviewed planar atlas registration and authored pigment.
46
+ It is not a captured iris of the generated character and has finite source resolution.
47
+
48
+ ## Review gate
49
+
50
+ Use the viewer's **Optical eyes · fit preview** option; toggling must preserve the camera.
51
+ Inspect front, both three-quarter views and profile; then gaze in both directions, half
52
+ blink, independent winks and full closure. Play the exported clip as well as testing sliders.
53
+ Check upper-lid contact, inner/outer corners, tear edge, iris parallax, refraction, texture
54
+ orientation, eyeball penetration and closed-lid normals. Check WebGL and WebGPU.
55
+
56
+ `highquality/tests/eye_fit_smoke.mjs` exercises the local viewer and writes screenshots.
57
+ Read those images: zero renderer errors does not establish good optical fit. Keep
58
+ `optical_fit_review_required` until visual checks pass. Next production work includes
59
+ regional scleral scattering, richer iris relief, fitting across characters, refined lid shape and composition with a complete facial/body rig. Do not call this MetaHuman
60
+ parity based on the presence of corneal transmission alone.
61
+
62
+ ## Separate source defects from optical defects
63
+
64
+ If a closed eyelid shows bright fragments, hide all generated optical layers temporarily.
65
+ If the fragments remain, inspect the original unlit face and material-region evidence.
66
+ Do not keep moving the eyeball to compensate for source albedo, normals or incorrect lid
67
+ labels. A bright painted streak and a geometric hole require different corrections.
68
+
69
+ A narrowly authored source-albedo defect can use a separate UV selection and
70
+ `texture_repair.py`: harmonic interpolation in linear light changes only selected texels,
71
+ with outside pixels byte-identical. Keep that selection separate from anatomical labels,
72
+ archive its projection evidence and inspect the repair. It does not reconstruct eyelid
73
+ geometry, lashes or missing detail. The djinn trial still requires eyelid surface work.
74
+ Eye profiles explicitly choose `skinRevision` so a later skin build cannot silently change
75
+ an already-reviewed eye fit. The current adapter accepts v2/v3/v4 and keeps output hashes.
76
+
77
+
78
+ Orbital backing must remain behind the recessed iris and pupil at every blink and gaze angle. Do not reuse the corneal-envelope eyelid deformation for backing tissue: even a small inset can still place it ahead of the iris. Validate partial blinks and isolate optical layers when diagnosing occlusion. Current prototype keeps its dense backing head-fixed. Continue its recessed depth envelope beyond the globe at the canthi too; retaining source-surface depth outside the globe can leave a visible triangle ahead of the closing lid.
79
+
80
+
81
+ Before generating blink targets, inspect the neutral lid/globe intersection. The playground
82
+ can opt into `conformOpenLids` to push intersecting tissue outside the explicitly fitted
83
+ globe. This is geometry fitting around authored landmarks, not automatic anatomical
84
+ recognition. Do not pull the surrounding orbital skin inward merely to follow a sphere;
85
+ keep a smooth support band and stationary canthi. Inspect partial and full closure anew.
86
+
87
+
88
+ The playground now exports gaze-follow lid targets as well as blink targets. The engine
89
+ uses `eyeLidLookUpLeft/Right` and `eyeLidLookDownLeft/Right` at ±0.35 radians pitch;
90
+ full closure suppresses gaze follow independently for each eye. Inspect both directions,
91
+ partial blinks and winks. A controller test validates channel ownership, not the surface fit.
92
+
93
+
94
+ ## Reconstructed lid bands (experimental playground option)
95
+
96
+ When the source eye margin is damaged, explicitly author a paired `outerLidPx` contour
97
+ around the existing `openingPx`. The outer contour must contain the aperture. The builder
98
+ ray-samples the original boundary and reconstructs only the intervening strip, preserving
99
+ its outer position/normal and following the fitted optical envelope at its inner edge.
100
+ This is designed topology and needs neutral, oblique, partial and full-blink inspection.
101
+ It does not recover missing anatomy automatically.
102
+
103
+ Source albedo can contain painted eye shadows or highlights. Stretching those into a
104
+ closed lid is a source-color defect. Optional `lidSkinSamplesPx` records at least three
105
+ explicitly reviewed clean skin donors in the same exact evidence view. Their linear colors
106
+ supply invented inner-lid pigment, blended to the sampled outer edge. Inspect the join;
107
+ never label this as scan-derived detail. The djinn trial still has outer-transition and
108
+ corner limitations. Keep this feature opt-in until its fit is acceptable.
109
+
110
+ For geometry diagnostics, hide cornea, sclera, iris, pupil, contact, tear and lashes, but
111
+ retain reconstructed `eyelid-skin`. Hiding that skin too produces an intentional hole and
112
+ invalidates the closure diagnostic. Inspect unlit albedo separately from geometry normals.
113
+ The playground regression now renders front, both obliques, profile, both yaw directions, and an oblique full blink. Eye review receipts must identify the exact selected output hash, including assembled
114
+ variants; a previous screenshot cannot validate an output rebuilt afterward.
115
+
116
+ ## Authored brow strands (playground option)
117
+
118
+ A painted brow can retain its color but still lack visible strand depth. The optional
119
+ `browGroom` on each fitted eye accepts an independently reviewed `polygonPx`, at least
120
+ two `combGuidesPx` start/end pairs in that same exact view, `strandCount`, `seed`,
121
+ `radiusM`, `lengthRangeM` and `colorLinear`. The local `brow_groom.py` ray-projects roots
122
+ onto the nearest visible source surface and projects the authored comb directions into
123
+ its tangent plane. It constructs tapered short fibers; it performs no hair recognition.
124
+ Do not classify a dark supraorbital shadow as a brow without inspecting the source.
125
+
126
+ Record these as designed hairs, inspect both sides and profile, and preserve the underlying
127
+ source. The strands attach to the head; they do not yet follow expressive brow morphs.
128
+ Fine strands can alias without temporal antialiasing or a filtered hair LOD. This prototype
129
+ is not a replacement for a production groom/simulation system. The b5359 trial uses a
130
+ separate medial-corner tissue surface too; review its fit during closure independently.
131
+ A reconstructed lid-band trial on b5359 was rejected because its pale angular transition
132
+ looked worse. Do not assume that enabling every optional reconstruction improves a fit.
133
+
134
+ ## Corner lining
135
+
136
+ A deep backing disk can leave a dark gap between the globe and the medial lid opening.
137
+ The optional `canthusWalls` profile lists explicit upper/corner/lower `contourIndices`
138
+ and a designed `colorLinear`. The narrow lining joins those reviewed source-lid points
139
+ to a recessed globe rim. Only the lid edge follows blink/gaze targets; the globe edge stays
140
+ fixed, outside the iris envelope over the reviewed ±0.35 radian gaze range. Do not apply
141
+ the corneal closure deformation to the whole socket. Inspect partial closure and both
142
+ obliques after fitting; source corners and dimensions differ between characters.
143
+ This is designed lining, not transferred scan anatomy. The CC0 MakeHuman topology was
144
+ visually inspected as an anatomical reference; no donor mesh is embedded by this option.
145
+ When a reconstructed lid band replaces the source margin, set its lining's
146
+ `contactMethod: "reconstructed-lid-v1"` to use the same aperture depth calculation.
147
+ Otherwise the lining can follow a removed source surface and protrude below the new
148
+ lid. This joins the support consistently; it does not supply a realistic caruncle or
149
+ make an oversized authored corner anatomical. Inspect those separately.
150
+
151
+ If a source has no separately classified ocular material, inspect the exact eye views
152
+ and explicitly set `openingAuthority: "reviewed-contours"`. The adapter then uses the
153
+ authored contours to remove the source surface. It still verifies source/image hashes
154
+ and rejects a cut that removes no interior triangles. Never infer the opening from
155
+ skin color or copy another character's contour; narrow hooded lids need their own fit.
156
+
157
+ Eyelid normal targets transport the imported shading normals with the shortest rotation
158
+ between the rest and deformed geometric normals. This preserves the imported normal's
159
+ angle to the surface while the lid moves. The neutral mesh retains its authored normals;
160
+ unused vertices keep their original normals. Inspect both the neutral and fully closed
161
+ pose after changing a fit, since valid normals cannot correct a poor anatomical shape.
162
+
163
+ Review each eye at eye-sized framing as well as face-sized framing. Inspect a neutral
164
+ eye and an oblique fully closed eye separately. A smooth globe can hide a polygonal
165
+ opening at face scale; a successful blink protocol does not establish anatomical quality.
166
+ In the playground, `CLOSE_EYES=1` adds these views and `REVIEW_SUFFIX` keeps experiments
167
+ separate. Use `SELECTED_EYES=1` to compare with the reviewed snapshot, rather than the
168
+ latest candidate. Explicitly unset `BACKEND` for a complete two-backend review.
169
+
170
+ An optional `contourRefinement` with `method: "convex-quadratic-v1"` and
171
+ `samplesPerLandmark: 8` rounds the segments between reviewed landmarks, staying inside
172
+ the original convex opening and preserving the two shared upper/lower eye corners.
173
+ For a reconstructed band, set `outerBoundary: "preserve-authored"` to retain every
174
+ segment of the reviewed outer source cut. Rounding that cut inward can leave pieces of
175
+ the damaged original eye margin behind. Paired outer points are then subdivided without
176
+ changing the cut; only the visible inner aperture is rounded. The older `rounded` outer
177
+ mode remains available for reproducibility, and requires its own review.
178
+ Indexed tissue chains are refined together. The fitted output
179
+ records the original points and maximum inset; it is safe to rebuild without applying
180
+ the refinement twice. This is a geometric interpolation of the agent's landmarks, not
181
+ an inferred anatomical contour. Inspect the result before selecting it: rounding alone
182
+ does not fix tissue depth, color, contact or deformation.
183
+
184
+ `outerEdgeSampling: "source-intersections-v1"` on an eye adds the original triangle-edge
185
+ crossings to the paired lid-band sampling. Its outer rim then follows the piecewise
186
+ source surface rather than bridging over small source ridges between uniform samples.
187
+ It preserves the authored cut and adds no anatomical selection. Keep checking the
188
+ closed pose: normal continuity and an actual eyelid fold need their own review.
189
+
190
+ If a designed `caruncle` is hidden behind an authored lining, its optional
191
+ `support: "corner-lining-v1"` positions it on the corresponding lining depth. It must
192
+ reference a corner in exactly one `canthusWalls` chain. The helper rejects centers
193
+ outside that lining's supported interval and rejects a tissue footprint that intersects
194
+ the iris envelope over the reviewed gaze range. Medial tissue may overlap peripheral
195
+ sclera; forcing it behind the entire sphere would hide it again and distort its shape.
196
+ The dimensions, placement and color remain explicit authored choices. This construction
197
+ is a prototype anatomical insert, not a scanned tear duct or a proof of eye realism.
198
+
199
+ For a reconstructed band that produces radial fan creases, `fairLidDepth: true`
200
+ uses harmonic depth fairing across the whole projected strip mesh. Both authored
201
+ rims remain fixed; projected columns interpolate the paired contours directly,
202
+ preventing independent Hermite tangents from bunching them at the canthi. The
203
+ result is refitted outside the optical envelope before computing normals and
204
+ blink targets. This is geometry repair, not a wrinkle texture filter. It does not
205
+ resolve an incorrect boundary shape or source pigment automatically. Inspect both
206
+ corners, neutral and full closure, obliques and gaze before selecting the asset.
207
+
208
+ A front silhouette alone cannot establish corner depth. `cornerDepths` optionally
209
+ records explicitly reviewed `pixel`, `depthM` (relative to the globe center, positive
210
+ forward), and `radiusM` for a corner. Local source support fades toward that depth;
211
+ the reconstructed lid and lining share a smooth tangent continuation from 85% of
212
+ the globe radius toward the corner. The curve stays outside the globe. Its angular
213
+ influence has a full-strength central half-width and smooth outer falloff. Inspect
214
+ both close lateral views (`SIDE_EYES=1`) and closure. Never assign these corrections
215
+ across characters without independently reviewing their actual depth and silhouette.
@@ -0,0 +1,115 @@
1
+ # Applying reviewed skin maps
2
+
3
+ The projection helper creates evidence and labels. It does not generate a body rig or
4
+ reconstruct missing anatomical detail. Keep source models immutable and store character
5
+ work outside this shipped skill, because GDK upgrades refresh the skill files.
6
+
7
+ ## Prepare the material revision
8
+
9
+ Use the project's existing character loader and material pipeline. In the Bitmagic engine,
10
+ read `agent-docs/character-surfaces.md` and use `RealisticCharacter.create(root, options)`
11
+ when that API is available. Do not assume a published engine version already contains it:
12
+ inspect the installed engine declarations first. Preserve working standard glTF materials
13
+ when the specialized adapter is unavailable and report that rendering integration remains.
14
+ Do not silently upgrade the engine or edit unrelated existing character types.
15
+
16
+ Author maps from licensed skin exemplars or the creator's own assets. Register the exemplar
17
+ to this character's reviewed facial landmarks and physical scale; never reuse another
18
+ character's target coordinates. Keep donor identity, tattoos, beard and complexion out of
19
+ relief transfer. Use anatomically appropriate detail for hands, palms, feet and body areas.
20
+ A generic repeated face tile is a preview fallback, not a finished regional detail library.
21
+ Retain attribution, source hashes, transformations and the authored physical amplitude.
22
+ For visible regional creases, the agent may author curves in exact evidence-image
23
+ coordinates and bake physically scaled relief onto independently labelled visible skin.
24
+ Record these as designed enhancements, not captured measurements. Keep glabrous palm
25
+ detail separate from facial follicles, and inspect the result at hand-sized framing.
26
+ The [regional detail helpers](regional-detail.md) evaluate authored crease curves and
27
+ licensed roughness patches without making anatomical decisions.
28
+
29
+ The source UV label map is top-left image data. Convert to the exporter/runtime's UV
30
+ convention exactly once. Bake source albedo as sRGB; roughness, metalness, masks, normals
31
+ and packed detail as linear data. Confirm with a known neutral patch and a source-material
32
+ comparison under identical lighting. A global saturation adjustment cannot diagnose a
33
+ color-space conversion bug.
34
+
35
+ ## Specialized engine contract
36
+
37
+ Explicit material extras opt into the character adapter. Untagged materials remain native.
38
+ For mixed skin/clothing primitives, `skinSurfaceBlend: true` uses atlas alpha as per-pixel
39
+ skin coverage. The packed linear RGBA atlas stores signed height around .5, roughness,
40
+ chromatic residual around .5 and coverage. `skinAtlasHeightRangeM` sets physical height.
41
+ `skinAtlasTexture` and optional `skinExpressionTexture` refer to embedded glTF texture
42
+ indices. `_FACE_UV` supplies atlas coordinates; `_FACE_WEIGHT` supplies coverage weighting.
43
+ `_SCATTER` is a fallback transmission attribute. Read the installed engine contract for
44
+ exact current fields rather than guessing their implementation.
45
+
46
+ Check physical texel density before increasing relief strength: a 4K full-body texture
47
+ can still sample the face at roughly half a millimetre per texel. In engines supporting
48
+ `skinFacialAtlasTexture`, retain the registered facial detail separately from body coverage.
49
+ The `skinFacialAtlasLayout: "detail-expression-halves-v1"` contract packs facial detail in
50
+ the left half and facial expression in the right half of one linear texture; its detail
51
+ height uses the same physical range as the body atlas. `_FACIAL_DETAIL` packs independently registered UV in XY and geometry-verified projection
52
+ visibility in Z, retaining the WebGPU vertex-buffer budget on skinned meshes.
53
+ This layer replaces facial detail baked into the body atlas, not skin coverage. Body
54
+ expression must be neutral for this layout. Packing replaces its shader sampler rather
55
+ than adding samplers beyond WebGL's budget. Compare the actual backends, preserve physical
56
+ filter widths when changing resolution, and check that coverage remains byte-identical.
57
+
58
+ The same packed texture can reserve additional rows for independently reviewed body
59
+ patches while keeping the original face texels. `skinFacialAtlasRegion` then records the
60
+ face rectangle within the detail half, and each vertex's `_FACIAL_DETAIL` coordinates
61
+ already address its assigned region. Reconstructed eyelids must use that rectangle too.
62
+ Keep patch alpha as detail blending only: the body atlas still owns skin coverage. This
63
+ retains the sampler and vertex-buffer budget instead of adding one material per patch.
64
+
65
+ Resolve embedded textures through the engine GLTF loader parser. Keep the scene diffusion
66
+ and transmission passes and the body AnimationMixer caller-owned. The adapter exposes
67
+ independent eye controls, preserves source materials on disposal, and does not create a
68
+ missing skeleton. Keep specular reflection outside diffuse scattering. A blurred beauty
69
+ image is not subsurface diffusion. Author channel diffusion ratios in asset metadata;
70
+ never infer skin type from character ID, race, height or RGB thresholds.
71
+
72
+ At a known skin/hair/lip boundary, material weights must sum to one; independent fades
73
+ expose the native response as a glossy line. Fill filtering gutters in UNUSED UV atlas
74
+ space from the nearest occupied texel, but never grow labels into unseen surface regions.
75
+ Check the actual zero-coverage and full-coverage endpoints against the native and skin
76
+ materials. Preserve armor, cloth, hair and optical surfaces during skin changes.
77
+
78
+ ## Source defects and acceptance
79
+
80
+ Separate source pigment spill, baked lighting, UV seams, normal errors, geometric creases
81
+ and missing coverage. Inspect unlit source, material labels and shaded results independently.
82
+ Color repair needs a separate authored selection. When a defect crosses UV islands, use
83
+ reviewed clean swatches in surface space; atlas-space harmonic fill may retain contaminated
84
+ island boundaries. A color repair cannot reconstruct missing hand geometry or eyelids.
85
+
86
+ Review all exposed regions and fixed-camera detail on both supported rendering backends.
87
+ Store region verdicts, current output hashes and review images beside the character. A
88
+ successful export or low conflict count is not visual acceptance. Keep incomplete regions
89
+ explicit and continue gathering views or authoring detail rather than calling a face-only
90
+ pass a complete character.
91
+
92
+ When a project uses the `viewerReady` metadata convention, `scripts/select_preview.py`
93
+ can validate the mechanical handoff. Supply `--asset`, `--metadata`, `--render-report`
94
+ and `--visual-verdict`. The render report is an array containing both `webgl` and
95
+ `webgpu` receipts with matching `actual`, empty `errors`, and the current `outputSha256`.
96
+ For combined runtime reports use `--variant eyes` or `--variant surfaces` to read
97
+ `assetHashes` instead. The agent-written verdict must identify the same output hash,
98
+ use `status: "local_preview_with_known_issues"` and `wholeCharacterAccepted: false`,
99
+ and list actually inspected images as `visuallyInspected: [{file, sha256}]`, relative
100
+ to that verdict. The helper checks current image bytes before selecting the preview.
101
+ It does not inspect those images, publish an asset, or declare the character finished.
102
+
103
+ Use the [installed exporters](exporters.md) to build these authored inputs into GLBs.
104
+ [The playground example](playground.md) records the tested asset layout and review harness;
105
+ its browser review commands still require that separate checkout.
106
+
107
+
108
+ ### Regional height composition
109
+
110
+ Independently registered body patches may declare `skinRegionalAtlasHeightMode: "additive-v1"` with `skinFacialAtlasRegion: [0, 0, 1, faceEndV]`, where `0 < faceEndV < 1`. The face occupies the atlas's top rows; body patches occupy rows below it. In those body rows, patch relief adds to the underlying body height rather than replacing authored palm creases or other regional folds. Facial relief retains replacement behavior, and body coverage is unchanged. Roughness still blends to the authored patch value. Assets without this explicit mode retain their previous replacement behavior.
111
+
112
+ This uses the existing packed texture and VEC3 binding on WebGL and WebGPU; it adds no sampler or vertex attribute. Do not compensate for erased crease layers by increasing microdetail strength. Check the composition with the patch enabled and disabled at the same camera, and retain the physical amplitude of each layer.
113
+
114
+
115
+ Regional bindings need coherent UV coordinates at every corner of a triangle touching the patch, including corners with zero detail weight. A zero-weight corner still participates in UV interpolation. Leaving its old facial coordinates in place can make the triangle sample unrelated atlas texels. Extend coordinate support by adjacent triangles while keeping their detail weight zero and semantic coverage unchanged; reject overlapping active patch bindings or split the geometry explicitly.