⛔ CERRADO (2026-07-02): las 6 tareas de este documento están HECHAS. No ejecutar nada de aquí. El roadmap vigente es
newtask.md(y la crítica de contexto está enideas.md). Se conserva solo como histórico; las "Trampas globales" siguen vigentes y están copiadas en newtask.md. Aviso: la capa de offsets por preset (T3) y las placas SVG de rasgos que estas tareas pulieron serán SUSTITUIDAS por decals en la Fase 4 de newtask.md — no añadir más presets/offsets sobre esa base.
Estado: 2.1, 2.3, 2.4 (pelo casco) y 2.10 (cuerpos PSX) hechas y commiteadas. Este documento detalla las 6 tareas siguientes en orden recomendado, con instrucciones suficientes para que las delegables las ejecute un modelo más barato sin contexto previo.
Reparto recomendado:
| Tarea | Quién | Motivo |
|---|---|---|
T1 Fix bundle eyeNoseGap |
Delegable | Ajuste numérico acotado + test que ya dice el valor esperado |
| T2 Moldes N64 paramétricos | Mixto | Andamiaje delegable; el ajuste visual de proporciones lo hace el modelo caro |
| T3 feature.json relativo + controles Mii (2.2+2.5) | Modelo caro sí o sí | Decisiones de formato/arquitectura, matemática de montaje, UI y persistencia entrelazadas |
T4 Auditoría visual en npm run check (2.7) |
Delegable | Las tolerancias quedan especificadas abajo; la implementación es mecánica |
| T5 Borrar ruta legacy SVG (2.6) | Delegable | Borrado mecánico con red de seguridad (hacer DESPUÉS de T4) |
| T6 Docs + cierre openspec (2.8+2.9) | Delegable | Redacción a partir de material existente; revisar ask-head.md al final |
- Alias del rig humanoide (
src/modules/viewport/templates.js,HUMANOID_NODE_ALIASES~línea 295): NUNCA nombrar piezas decorativasSHOULDER_L/R,PAULDRON_*,CLAVICLE_*,WAIST,LEFT_SHOULDER, etc. El normalizador reparentaARM_Lbajo el nodo clavícula y un nombre coincidente crea un ciclo que desmonta el brazo entero (síntoma: warningsAnimation target ARM_L not found in group). Usar sufijos tipoARM_L_PAD,TORSO_WAIST. faceColorses un ARRAY de hex (6 colores = 1 por quad, en orden back/front/left/right/top/bottom segúnTRI_FACES). Para moldes generados se rehornea desde la paleta conmakeFaceColors(baseColor)exportado porsrc/data/templates/generated-character-molds.js(gate:PALETTE_DRIVEN_MOLD_IDSenavatar-builder.js). Los moldes JSON conservan sus arrays a mano.- Precedencia de color (
resolvePaletteColorTokenensrc/modules/avatar/avatar-builder.js): las reglas por nombre de pieza (HAND/NECK→skin, FOOT→accent, PELVIS→bodySecondary,_PAD→bodyPrimary, BELT/COLLAR/RIBBON→accent) van ANTES queslotColorMap[slotId]. No reordenar. - Sweeps de captura visual (PowerShell 5.1, sin
&&):- Cabezas:
$env:CAPTURE_HEADS='1'; npx playwright test avatar-head-capture --reporter=line→.tmp-head-views/avatars/ - Cuerpos:
$env:CAPTURE_BODIES='1'; npx playwright test avatar-body-capture --reporter=line→.tmp-head-views/bodies/
- Cabezas:
- Dentro de
page.evaluateNO funcionaimport('three')ni existestate.THREE. Para bounding boxes en mundo, copiar el patrón manual detests/e2e/avatar-body-capture.spec.js(esquinas degeometry.boundingBox×node.matrixWorld.elements, column-major). - Flake de arranque:
helpers/app.jsasserta#canvasvisible con timeout 5s y el vite server arranca frío en cada run (reuseExistingServer:false). Si falla el bootstrap, re-ejecutar una vez antes de buscar bugs. - Suites de regresión:
npx playwright test avatar-forge-mold-mode avatar-forge-placement --reporter=linedebe dar 16/16 una vez hecha T1 (hoy 15/16 por el fallo que arregla T1). Despuésnpm run check. - Commits: mensaje descriptivo (nunca "work in progress"), terminar con
Co-Authored-By:del modelo que firma. Branch:fable/fixing_problems. - NO tocar el Problema 1 (mocap/skeleton capture) ni nada bajo esa área de task.md.
Síntoma: avatar-forge-placement.spec.js:327 ("defines readable mold feature bundles")
falla: psx_mesh_soft_default_01 eyeNoseGap = −0.0878, esperado ≥ 0. Es decir, en el bundle
por defecto los ojos (wide_01) y la nariz (nose_soft_01) se solapan verticalmente.
Archivos:
src/data/avatar/catalog/mold-feature-bundles.js— define el bundle (combinación de presets).src/data/avatar/catalog/head-molds.js—MESH_PORTRAIT_PART_PRESET_OFFSETS(~línea 60-87): offsets por preset (y,scaleX,scaleY,originX/Y) que se aplican sobre el montaje por landmarks.- El test mide gaps reales construyendo el avatar; leerlo (líneas ~327-435) para ver cómo calcula
eyeNoseGapantes de tocar nada.
Pasos:
- Ejecutar solo ese test y confirmar el −0.0878.
- Opción A (preferida): en
MESH_PORTRAIT_PART_PRESET_OFFSETS, subir ligeramente los ojos (wide_01:ymás negativo) y/o bajar la nariz (nose_soft_01:ymás positivo) en pasos pequeños (~2-4 unidades SVG) hasta queeyeNoseGap ≥ 0sin romperbrowEyeGap ≥ −0.02ninoseMouthGap ≥ 0.015(el mismo test los comprueba todos). Opción B (solo si A deforma la cara): cambiar el preset de nariz del bundle a otro más corto. - Validar: el test de placement completo en verde (16/16 junto con mold-mode), y
sweep
CAPTURE_HEADSmirandopsx_mesh_portrait_*_front.png: ojos y nariz separados, cara natural. Adjuntar/conservar las capturas para revisión. npm run check. Commit.
Criterio de éxito: 16/16 en las dos suites de avatar + captura frontal sin solape visible.
Síntoma: n64_classic y n64_round (JSON a mano en src/data/templates/characters/ n64_humanoid_mold_cm.json y n64_body_mold_cm.json) quedaron muy por detrás de los 4 moldes
PSX generados: brazos tipo maza flotante, sin manos diferenciadas, silueta pobre
(ver .tmp-head-views/bodies/n64_classic_front.png).
Objetivo: portarlos al generador paramétrico de src/data/templates/generated-character-molds.js
con estética N64 (referencia Mario 64 / Ocarina low-LOD): torso ovalado/ancho, cuello corto o
inexistente, manos grandes tipo guante, pies grandes, menos segmentación que los PSX.
Parte delegable (andamiaje):
- Añadir 2 variantes nuevas a
MOLD_VARIANTSengenerated-character-molds.jsreutilizando los builders existentes (makeChestMesh,makeLimbMesh,handPiece, etc.). Ids nuevos:n64_humanoid_round_mold_cmyn64_humanoid_classic_mold_cm(NO reutilizar los ids JSON viejos todavía). Specs iniciales: copiar la del chibi y ensanchar torso / agrandar manos y pies. - Apuntar los presets
n64_classicyn64_rounddesrc/data/avatar/catalog/body-presets.jsa los ids nuevos. - Ejecutar el sweep
CAPTURE_BODIES, las dos suites de avatar ynpm run check. Los JSON viejos se quedan en el repo (otros templates pueden referenciarlos; comprobar con grep antes de plantear borrarlos — si nada más los usa, proponer su borrado en el commit message).
Parte para el modelo caro (no delegar): iterar las specs sobre las capturas hasta que la
silueta "dé el pego" N64 (proporciones, redondez del torso vía bottomWidth/topWidth,
tamaño relativo cabeza/manos), y decidir si los moldes JSON viejos se borran o se renombran.
Criterio de éxito: capturas front/profile/three-quarter de ambos presets N64 con calidad
comparable a los PSX; suites en verde; npm run check pasa (ojo: el audit cuenta 289 templates —
si se borran JSON habrá que ver si el contador es dinámico o hay lista fija).
Resultado: escala relativa al cráneo (resolveFeatureRelativeSizeFactor en avatar-builder.js,
clamp 0.75–1.35, solo rasgos faciales) + offsets/spacing de los sliders Mii convertidos a
desplazamientos relativos a la interocular en buildLandmarkMountPlan
(svg-head-integration.js). Los sliders ya existían en la UI y persistían en
recipe.features[key].placement; lo que faltaba era que el recentrado por landmarks no los
anulara en 3D. Test nuevo: «applies Mii placement sliders and skull-relative sizing» en
avatar-forge-placement.spec.js. Limitación conocida (relevante para T6/docs): los sliders de
pelo no afectan al casco procedural de hair-helmet.js.
Contexto original (ya ejecutado): no delegar. Razones: decide el formato feature.json (contrato para todo lo posterior, incluido
el prompt LLM de T6), toca la matemática de buildLandmarkMountPlan
(src/modules/svg/svg-head-integration.js), el esquema de avatarRecipe (persistencia y
migración de recetas guardadas), y la UI del forge — todo acoplado y con criterio visual fino.
Alcance resumido (para planificación, no para ejecutar):
- 2.2 — tamaño relativo: cada preset de rasgo declara su tamaño proporcional a la distancia
interocular (
|eyeR − eyeL|) o al bounding del cráneo de la cabeza destino, en vez de píxeles absolutos del SVG. Aplicarlo en el plan de montaje de landmarks. MigrarMESH_PORTRAIT_PART_PRESET_OFFSETS(que T1 acaba de ajustar) al nuevo esquema. - 2.5 — controles Mii: 4 deltas por rasgo (size / up-down / left-right / spacing) aplicados
sobre el landmark, persistidos en
avatarRecipe.features[key]junto alpresetId. UI: sliders en el panel del forge solo en modo molde. - Validación: sweep de cabezas con deltas extremos (±máximo) sin que ningún rasgo salga de la cara; los gaps del test de placement siguen cumpliéndose con deltas en 0 (compatibilidad).
Objetivo: que npm run check falle si un rasgo se sale de la tolerancia de su landmark,
usando la infraestructura que ya existe (sweeps Playwright + audit scripts de scripts/).
Especificación (fijada, no inventar otra):
- Nuevo script
scripts/avatar-visual-audit.mjso test Playwright NO gateado por env var (decidir según lo que ya consumascripts/check-release-readiness.mjs; integrarlo en la cadena delnpm run checkigual quetemplate-asset-audit.mjs). - Para cada cabeza registrada × bundle por defecto: construir el avatar (headless, como hacen
los tests de placement) y medir en espacio canónico de cabeza:
- centro de cada rasgo vs su landmark: distancia ≤ 0.18 (unidades de cabeza canónica, altura 1.2);
- los mismos gaps del test de placement (
browEyeGap ≥ −0.02,eyeNoseGap ≥ 0,noseMouthGap ≥ 0.015,mouthBottom ≤ 0.9,earTop ≥ 0.38) — reutilizar/extraer esa lógica a un helper compartido en vez de duplicarla; - ningún vértice de rasgo por debajo de
chin.yni por encima decrown.y + 0.1.
- Guardar screenshots de comparación en
.tmp-head-views/audit/solo en modo verbose/CI-fail (no en cadanpm run checkpara no ralentizarlo; medir primero cuánto tarda). - Si la auditoría duplica >50% del test
defines readable mold feature bundles, consolidar: el test e2e puede quedarse como smoke y la auditoría ser la fuente de verdad.
Criterio de éxito: npm run check pasa hoy; introducir a mano un offset roto (p. ej. nariz
y −40) hace que falle con mensaje claro; revertirlo lo deja en verde.
Objetivo: eliminar el catálogo amplio de head-shapes, la cara SVG completa como base y las
familias PSX/N64/Bridge como eje del builder. Estamos pre-1.0: se acepta romper recetas guardadas.
Pasos:
- Inventario con grep: quién importa
head-shapes.js, quién usasourceHeadShapeId, rutas legacy enavatar-builder.js(createAvatarHeadSourcepor SVG-shape vs mold) y en el panel del forge ("modo legacy" — hay un test que lo cubre: "keeps legacy avatar recipes editable while disabling mold-only controls"). - Borrar en capas: primero UI (entradas de catálogo/selector), luego builder, luego datos.
Tras cada capa: las dos suites de avatar +
npm run check. - Los tests que cubren explícitamente el modo legacy se borran o reescriben hacia mold-mode (decisión simple: si el test solo existe para la ruta borrada, se borra con ella).
- Si una receta guardada legacy llega al builder, debe fallar con mensaje claro o migrarse a un molde por defecto — elegir UNA de las dos y documentarla en el commit.
Criterio de éxito: no quedan referencias a head-shapes/familias legacy (grep limpio),
suites en verde, npm run check (incluida la auditoría T4) pasa.
docs/HEADS.md: documentar el pipeline real: formatohead.json(geometría +axes+ los 9 landmarks: eyeL, eyeR, noseTip, mouth, earL, earR, hairline, crown, chin; espacio canónico +Y up / +Z cara / altura 1.2 / base y=0),scripts/derive-head-landmarks.mjs, formatofeature.json(el que defina T3 — si T3 no está hecha, documentar el estado actual y marcar la sección como provisional), pelo-casco (hair-helmet.js, 5 estilos), y los sweeps de captura. Seguir el patrón de los docs existentes de objetos/animaciones.ask-head.md: prompt autocontenido para que un LLM externo genere unahead.jsonválida: ejemplo completo de cabeza pequeña, rangos de proporción aceptados, checklist con los umbrales de la auditoría T4. Mismo patrón que elask.mdque ya funciona para objetos.- 2.9 openspec: revisar los 2 changes activos de avatar (
avatar-head-mold-feature-controls,avatar-forge-feature-placement-workflow) conopenspec list/openspec status. Lo ya implementado por otra vía → archivar (skill/opsx:archive, sincronizando specs); lo aún vigente → actualizar el delta a este diseño por landmarks. No abrir changes nuevos sin necesidad.
Criterio de éxito: un LLM sin contexto puede producir una head.json que pase la auditoría
T4 siguiendo solo ask-head.md; openspec list sin changes obsoletos.