Maya retopology and UVs
Expert retopology is a loop plan with the fewest polygons that still deform: landmarks first, rings
around eyes and mouth, three loops per joint, poles where nothing moves, a bend test that says whose
fault a bad crease is. Expert UVs spend texels where the camera looks, at a density derived from the
closest shot, with padding that survives mips. Without a mouse the agent reuses approved topology,
builds from data, and measures then renders every stage. If a sibling skill named here is missing
from your available skills, ask the user to install it
(npx skills add scenario-labs/skills --skill <name>); unattended, proceed from tool schemas and
flag the gap.
REQUIRED BACKGROUND: scenario-maya-expert (execution channel, review loop, 2027 version traps).
Toolkit: scripts/mx_retopology_uv.py
(import mx_retopology_uv as RU), built on mx_audit, mx_review and mx_run.
Status (2026-09-24): every Maya call is not yet run in Maya (not installed); 99 pure and 40
fake-Maya checks pass offline. First run tests/code/maya-retopology-uv/run_all.sh, then fix what
job_probe_commands reports.
Stance (the expert delta)
- Landmarks first, big polygons, then fill like a puzzle. FlippedNormals: starting small is "a
terrible way to work"; loose is recoverable, tight is not (9N4rG5qHWgk [00:01:05] [00:02:07]). The
loop map is data before any vertex; a template fit is gated at base density before spans are
added.
- Reuse approved topology. FlippedNormals carry one perfect hand, ear or base mesh to every
model ([00:10:11]); Jessica Dru Johnson's standard base cut face skinning from three days to 30
minutes (ZiYEO49B768 [00:58:51]). Quad Draw substitute:
RU.fit_template.
- No automatic topology on what deforms. On a face it "will look normal, but it's not"
(FlippedNormals [00:23:15]); automatic is for parts that do not animate ([00:22:13]). Retopologize
serves props, armor plates, static cloth; on a torso or loose coat it is a flagged start that must
pass the deformation gate.
- Isolate and bound deformation. Concentric rings around eyes and mouth, one control plus two
support loops per joint, a flat loop from lip corner to jaw corner against shearing (Jessica
[01:15:51] [01:30:10]), equal lid loop counts (FlippedNormals [00:21:41]). Poles in still areas or
skin folds ([00:12:45]); triangles only in cavities; never n-gons: ZBrush triangulates them and
blend shapes break ([00:05:31]).
- Test the bend before handoff, blame the right artist. antCGi: loops running along a joint
(wrist, ankle, hip crease) are the modeler's fix; volume lost at a correctly looped hinge is the
rig's, for correctives; prove it by swapping topology under identical weights (x07USYlvu2o
[00:10:27] [00:16:24]). Fit lids over the real eyeballs, with enough loops to curve over the
cornea on a blink ([00:15:18]; RlNnp4qQIrU [00:08:24]). Shear (Jessica [01:13:06]) judges face
hinges; on limbs a linear blend shears even perfect rings [added, measured].
- Retopologize traps (Maya 2027 Help).
polyRetopo re-runs on edits and file open: delete
history; Pause the node while changing several attributes. Preprocess Mesh (default on) smooths
detail: noisy 100k+ triangle input only. Hard surface 1 / 1 / 0. Never half a mesh. Edge component
tags steer flow.
- Texel density from the closest camera. Paulino: frame the reference piece at the closest shot,
double its screen pixels, round to a power of two, Get/Set on every shell (iL2iXizf9xM
[00:02:33]). Film: one density, UDIMs. Games: uniform, scale up the head, stack mirrored shells
(MLC s_KLbTUdKms [00:10:57]).
- Padding is a mip problem; bake prep is geometry. 4 px between shells, 2 px to the border,
doubled per mip step; Room space stays 2 px (Maya 2027 Help). Hard edges on UV seams, one
triangulation for bake and export, the whole mirrored model baked with mirrored UVs one tile over
(Polycount), a low that hugs the high (On Mars YDu9pYMkkSM [00:17:45]).
Establish first
| Input | Why it changes the plan | Default when the brief is silent |
|---|
| Purpose | film cage subdivided at render vs real-time triangles plus bakes | real-time |
| Deformation, engine | face rig, blend shapes; one extra mouth-corner span forced a fifth influence (Jessica [00:59:24]) | face and limbs deform; 4 influences, confirm with scenario-maya-rigging |
| Budget | triangles from the lead (Polycount); "exactly as high as needed" (FlippedNormals [00:13:46]) | propose one from screen coverage, as an assumption |
| Closest shot | texel density | 1920 x 1080, 85 mm on the head (Paulino) |
| Textures | map size, 0-1 or UDIM, lowest mip, strategy (optimized, technical, continuous) | games: 0-1 seen at a quarter size; film: 4K UDIMs; characters continuous |
| Template, eyes | base mesh; eyeballs to fit lids on | ask scenario-maya-modeling for a primitive-blocked base and eyeballs |
| Pose | neutral face, relaxed A-pose, eyes forward (Jessica [01:00:30]; antCGi e74KphYwMww [00:07:39]) | report a posed source |
Clothes fused to the body (AI meshes). Tight garments become body topology with loops on the
garment lines; loose layers get their own tube or template projected onto the fused source [added];
plates may slide but the torso stays one piece (Jessica [00:44:17]); wrinkles that never animate go
to Retopologize or the bake (FlippedNormals [00:22:13]).
Workflow
-
Intake, read only. mx_audit.audit(source); the source stays the bake source.
RU.prep_source makes the working copy (weld, soften, report non-manifold); a broken source is
rebuilt or used only as projection target (P2). Orient by the transform (cm, Y-up, +Z front, feet
at 0). GATE: numbers written; clay sheet looked at.
-
Map. Landmarks, ring counts per opening, joint stations, flows (mouth corner under the cheek;
neck along the sternocleidomastoid, clavicle to skull back, antCGi RlNnp4qQIrU [00:09:32]
[00:37:43]), a method per part. GATE: the map is JSON before any geometry.
-
Build per part.
| Part | Method | Call |
|---|
| Face, head, hands, body with a base | landmark fit | RU.fit_template |
| Limbs, fingers, sleeves, skirts, tails | plane sections, 1 + 2 loops per joint | RU.limb_stations, RU.build_tube |
| Props, armor plates, static cloth | Retopologize | RU.retopologize(mesh, faces, hard_surface=...) |
| Torso or face without a base | primitive base from scenario-maya-modeling, then fit | Retopologize only as a flagged start for Quad Draw (gui-paths.md) |
Then cavities: mouth bag, nostrils, eye pouch (FlippedNormals [00:25:16] [00:27:22]). GATE:
mx_audit.verdict clean per part.
-
Relax, center, mirror. RU.relax_project, RU.snap_center, RU.mirror_half (weld 0.001,
antCGi QW8w15J00Ok [00:02:56]); combine symmetric parts (e74KphYwMww [00:24:32]). GATE: no center
drift, symmetry 100%.
-
Gate the topology. RU.retopo_report plus wire and clay sheets in the source's views.
-
Deformation-ready gate, before UVs (antCGi unwraps after it).
RU.deform_test(mesh, chain, bends, review_dir=...) per limb (elbow and knee at 90 and 130
degrees, wrist, ankle, hip; twist judged mid-limb, never at shoulder or wrist, x07USYlvu2o
[00:08:40]), kind="hinge" for jaw open, RU.lid_check(head, eyeball). Proxy weights, no
skinCluster: binds are scenario-maya-deformation's. GATE: no topology verdict, lids ok, pose
sheets looked at; rig verdicts travel as notes; prove a fix with RU.compare_variants (P19,
P20).
-
UVs. Seams as edge loops (RU.loop_keys, RU.cut_seams): neck base, head slits, inside the
mouth, sleeve line, back of the arm, wrists, waist, inner legs, boot tops, soles (MLC [00:01:37]
to [00:08:05]); cloth on its real seams (Paulino [00:05:16]). RU.unfold, RU.optimize; limb
shells RU.orient_shell then RU.straighten_rows (MLC [00:04:49]);
RU.mirror_uvs(mode="mirror"). GATE: planned shells, no folds, distortion in band.
-
Density and packing. RU.density_from_camera (film) or RU.density_for_budget (games);
RU.set_texel_density (head bias in games); RU.layout(scale_mode="off") with RU.mip_padding;
UDIMs, or RU.mirror_uvs(mode="stack", offset_u=1.0) for game bakes, never where AO or a logo
differs; RU.lightmap_set. GATE: RU.uv_report ok; UV and RU.checker_review sheets looked at.
-
Bake prep. RU.harden_uv_borders, RU.bake_check, RU.make_cage or
RU.project_to_surface, RU.bake_copy, RU.overlap_review(low, high, out) (P21). GATE: high
inside the cage, hard edges only on seams, one triangulation, silhouettes match.
AI character end to end: procedure P18.
Numbers
| Item | Value | Relative to, source |
|---|
| Joint loops | 1 control + 2 support; knuckles 3 each | each bend (Jessica [01:15:51] [01:17:34]) |
| Lids, lips | upper count = lower count | FlippedNormals [00:21:41]; antCGi RlNnp4qQIrU [00:05:22] |
| Mirror, center | weld custom 0.001; drift band 1e-4 to 1e-2 cm, snap to 0 | antCGi QW8w15J00Ok [00:02:24]; FlippedNormals [00:19:06] |
| Retopologize | hard surface 1 / 1 / 0; Preprocess for 100k+ tris; tolerance under 10% is slow | Maya 2027 Help |
| Texel density | 2 x screen px at the closest shot, power of two | Paulino [00:02:33] |
| Maps, padding | 4K tiles, odd shell at half scale on 8K; 4 / 2 px, x2 per mip (2048 seen at 512: 16 / 8) | Paulino [00:05:48]; Maya 2027 Help |
| Hard edges, mirror | every UV seam, bends over ~45°; mirrored UVs 1 unit over | Polycount |
| Deformation [added] | joint loop within 20° of the bone, no spiral over 15°, 0.8 of an ideal ring's area kept; hinge mean shear under 10°; faces under 0.3 area collapse; an ideal ring under 0.7 is a rig note | organic digest; scenario-maya-deformation |
| Lids [added] | nothing inside the eyeball at rest or blink, vertices and edge midpoints; gap under 0.1 eye radius | antCGi x07USYlvu2o [00:15:18] |
| Gates [added] | deviation under 10% of mean edge; UV area ratio 0.5 to 2, anisotropy under 2; density within 10%; packing 0.7; 3+ clean rings per opening; silhouettes differ under 2% | this skill |
Quality gates
In code (MAYA, not yet run in Maya):
rep = RU.retopo_report("body_geo", "scan_high", openings={"eye_L": {"point": (3.2, 163, 8.5)}},
joints={"elbow_L": {"center": (45, 140, -2), "axis": (1, 0, 0), "radius": 6}})
dt = RU.deform_test("body_geo", [shoulder, elbow, wrist, hand_tip],
[{"name": "elbow_130", "joint": 1, "angle": 130, "axis": (0, 1, 0)}])
lid = RU.lid_check("body_geo", "eyeL_geo")
uv = RU.uv_report("body_geo", 4096, smallest_mip=1024, target_density=20.48, images_dir="/abs/out/uv")
print(rep["fails"], dt["verdict"], lid["fails"], uv["fails"]) # full arguments: procedures.md
Topology: 0 n-gons, no polyRetopo history, 3+ clean rings and equal halves per opening, 3 loops
per joint band, triangles only in cavities, eyes denser than the cranium, no center drift, no
topology verdict. UVs: all faces mapped, no unintended overlap, padding at the lowest mip, density
on target, hard edges only on seams (games). Visual: wire and clay sheets (rings close, even
squares); pose sheets (creases where anatomy creases, no pinching); UV sheets; checker in three
views plus the closest shot; overlap diff images (red: high outside the low). Score with
references/critique.md.
Common mistakes
| Mistake | Looks like | Fix |
|---|
| Retopologize on a face | plausible grid, no rings | template fit; openings gate |
polyRetopo history kept | mesh re-solves on edit or open | RU.retopologize deletes it |
| All hard edges on a scan or AI mesh | Retopologize fails or crawls | prep_source softens all |
| Cleanup and Merge on internal faces | endless non-manifold loop | select-mode Cleanup, delete by hand, or Boolean Volume (P2) |
| Wrist or ankle bend sent to the rigger | loops along the joint patched with correctives | topology verdict: reroute loops across it, A/B |
| Clean rings rebuilt for volume loss | same elbow collapse | rig verdict: corrective note for scenario-maya-deformation |
| Lids modeled without the eyeball | lid pops through on a blink | lid_check, add lid loops, refit |
| Center drift; relax after UVs | mirror seam; textures swim | snap_center first; relax before UVs or transfer_uvs |
| Straighten UVs on a whole shell | "this mess" | orient, align rows, pin, optimize the interior (MLC) |
| Unfold refuses a mesh that audits manifold | Unfold3D aborts | it unfolds a triangulated copy: triangulate a duplicate, select-mode Cleanup |
| Layout Uniform after density; stacked unique bakes | density changed; mirrored AO | scale_mode="off"; stack by strategy, offset 1 tile |
| Half model baked, two triangulations | center seam, zig-zag shading | whole mirrored model; bake_copy |
Handoffs
- Receives from scenario-maya-modeling (base meshes, eyeballs,
mx_validate(profile="model")
clean), scenario-zbrush-expert (real scale, neutral; posed sources go back), scenario-3d (FBX or
OBJ [verify glTF]; its remesh only for static parts); loop faults back from
scenario-maya-deformation with pose and numbers.
- Delivers to scenario-maya-rigging and scenario-maya-deformation: a new version,
<part>_geo
frozen without history, cm, Y-up, centered, feet on the grid, eyes separate and forward, mouth
bag, symmetric parts combined; retopo_report, deform_test (rig notes: hinges needing
correctives) and lid_check JSON, wire and pose sheets.
- Delivers to scenario-maya-lookdev: UV sets, px/cm, UDIM table, the bake package (high,
triangulated bake copy, cage, offsets, tangent basis: MikkTSpace for Unreal and Unity; Arnold
normal_map has a MikkTSpace mode from MtoA 5.6.1.1, Maya 2027.1), uv_report JSON.
Maya 2027 notes
- Quad Draw is interactive only (Make Live first); its 2027 hotkey table is lost, so gui-paths.md's
2018 panel is [verify].
polyRetopo flags are unsaved: RU.call passes only flags cmds.help
lists. Flow Retopology (cloud, 2027.1) needs a sign-in: not headless. Reduce is decimation.
- Broken source: Mesh > Booleans Volume mode with a Voxel size (2026) rebuilds watertight but needs
a second input; Mesh > Remesh evens the spread before Retopologize.
- Unfold3D is the default, refuses non-manifold meshes, pins unselected UVs (Legacy: selected only).
Relax is Optimize > Legacy. Texel Density needs Map Size first; Measure has Pixel Distance.
dgaTension (2026.3) measures stretch against a reference mesh for a heat map (RU.tension_node,
attributes [verify]). A hand-made test bind leaves Skin Tools layers uninitialized (the default),
so skinPercent floods work; on a skinned mesh delete Non-Deformer History, never History (antCGi
[00:12:41]).
References
references/procedures.md: full code P0 to P21 with test paths. Load
before writing code.
references/expert-notes.md: principles by expert, disagreements,
deciding conditions. Load when planning a face, body, clothes, a deformation test or a mapping
strategy.
references/critique.md: the self-review rubric. Load at every review.
references/gui-paths.md: menus, hotkeys, tool settings (Quad Draw,
Retopologize, test bind, UV Toolkit).
references/sources.md: every source with credentials, URL and
timestamps.