Animación Roblox, sin cabeza (headless)
¿Primera vez en esta máquina? Lee
LOCAL.mden esta carpeta. Si no existe, ejecuta el skillroblox-skills-setup(o copiaLOCAL.template.mdaLOCAL.mdy complétalo).LOCAL.mdcontiene tus rutas y ubicaciones de herramientas; es tuyo y nunca se comparte.
Autor de animación como datos (una especificación JSON de poses a lo largo del tiempo), hornéala en una Acción real de Blender, renderízala y mira el resultado antes de creértelo.
El bucle es: autor → renderizar cada fotograma → unir en una hoja de contacto → mirar → corregir → repetir. Todo aquí existe porque algún paso de ese bucle atrapó un fallo que todas las demás comprobaciones pasaron por alto.
Lee esto primero: la trampa que más tiempo hace perder
La mayoría de los rigs de Roblox traen una Acción de Blender con su pose de reposo. Blender re-evalúa esa Acción durante el renderizado. Así que, si estableces valores de pose y luego renderizas:
- cada sonda numérica reporta que tu pose se aplicó perfectamente
- cada fotograma renderizado muestra la pose predeterminada del rig
- los datos y la imagen nunca coinciden, y no hay ningún error
Limpiar la Acción tampoco ayuda, porque esa Acción ES la pose de reposo — si la limpias, las extremidades colapsan en el torso.
La solución: inserta FOTOGRAMAS CLAVE en esa misma Acción, luego usa frame_set() por fotograma y renderiza. La animación es entonces la Acción, nada puede sobrescribirla, los huesos no tocados mantienen sus valores de reposo por extrapolación constante, y terminas con una Acción real — que es lo que necesita una exportación a Roblox de todos modos. scripts/anim_render.py ya hace esto.
Lista completa en references/traps.md — 28 de ellas. Léela antes de depurar cualquier cosa.
Animar en FK. No en IK.
Una KeyframeSequence de Roblox es un árbol de rotaciones por articulación, una por Motor6D. Eso es FK. Cada rig R15 tiene un hueso de control por articulación para coincidir. Si manejas el personaje con objetivos IK, estás haciendo un viaje de ida y vuelta a través de un solucionador que Roblox nunca pidió, y pagando por ello:
- los objetivos IK solo de posición dejan el ROLLO de la extremidad libre, por lo que las partes cúbicas de Roblox presentan la cara que el solucionador elija y cambian entre fotogramas. En un avatar texturizado, eso se lee como colores que cambian instantáneamente — el síntoma que hace que una animación parezca con errores
- el solucionador salta entre ramas igualmente buenas fotograma a fotograma, por lo que las extremidades saltan mientras que cada fotograma aún se verifica perfectamente
- es lento
FK no tiene ramas, ni singularidades, ni ambigüedad de rollo, es exactamente 1:1 en grados, y se exporta directamente a Roblox.
La mayoría de los rigs vienen en modo IK, lo que hace que cada hueso FK_* se lea como inerte. Cambia el interruptor — no concluyas que FK está muerto:
"properties": {"ARM_IK_FK.L": 0.0, "ARM_IK_FK.R": 0.0,
"LEG_IK_FK.L": 0.0, "LEG_IK_FK.R": 0.0}
Medido en un rig R15 comunitario gratuito, y uniformemente agradable: cada extremidad descansa apuntando recto hacia abajo; en cada hueso FK_*, X negativo se balancea hacia adelante, Z positivo se balancea hacia la derecha del personaje, 1:1 en grados, idéntico en ambos lados — sin inversión de espejo. Los ángulos hijo son relativos al padre.
La lección general, sea cual sea el rig que uses: si un hueso de control está inerte, busca un interruptor que lo deshabilite antes de descartarlo. Los rigs estilo Rigify R15 llevan propiedades personalizadas ARM_IK_FK / LEG_IK_FK que por defecto están en 1.0 (IK). Ponlas a 0.0, ponles fotogramas clave (para que frame_set no pueda revertirlas), y anima en FK. Las convenciones de dirección anteriores se midieron en un rig; calibrate_rig.py y sweep_control.py las vuelven a medir en el tuyo, así que ejecútalos en cualquier rig que no hayas usado. La ruta de tu rig .blend va en LOCAL.md.
Usa IK solo cuando una extremidad deba alcanzar un punto mundial exacto. Entonces lee las trampas 12–15.
Haz que se vea como Roblox, no como la referencia
- 30 FPS, y un movimiento de combate dura 0.3–0.7s. El Editor de Animación por defecto está a 30fps. El tiempo de la vida real es demasiado lento para un juego. Toma la mecánica de cómo funciona realmente el movimiento; toma el tiempo de Roblox.
- Cinco poses: idle (reposo), anticipación, contacto, seguimiento, recuperación.
- Facilidad por segmento —
"ease": "in"para acelerar hacia el golpe,"out"para asentarse. Un smoothstep fijo desacelera en cada fotograma clave, por lo que el golpe se suaviza hasta detenerse en su propio fotograma de contacto y todo se lee blando. - Exagera. La animación de combate real de Roblox va mucho más allá del rango humano y se lee en la silueta.
- Renderiza en gris liso (
"plain": true). Una textura de avatar ocupada convierte un rig cúbico en un revoltijo ilegible y terminas depurando el disfraz en lugar de la pose. Las animaciones reales de Roblox se muestran en un maniquí liso exactamente por esta razón.
references/pose-recipes.md tiene los números reales — tablas de ángulos medidas para guardia, anticipación, cámara, contacto y seguimiento, el esqueleto de tiempo, y las dos reglas que atrapan a la gente (hombro + codo deben mantenerse por debajo de ~120 total; una patada alta necesita UpperLeg X por debajo de −120 o la pierna se fusiona con el torso). Empieza desde ahí y ajusta contra la vista previa. No los redescubras.
Sé rápido — medido, no adivinado
Todo el bucle son segundos. Si una pasada lleva minutos, algo anda mal. Medido en una PC de gama media, una animación de 24–36 fotogramas:
| etapa | tiempo | notas |
|---|---|---|
| Blender carga el rig | 0.7s | el inicio nunca es el problema |
| sonda numérica (mapa de control FK completo) | 0.1s | haz preguntas al rig con números |
renderizado de vista previa ("preview": true) | 4–6.5s | 1 vista, 320x240, 1 muestra |
| renderizado completo, 2 vistas a 640x560 | 9–17s | haz esto una vez, al final |
| codificación GIF | 0.3s | |
to_roblox.py → Luau | 0.1s | |
| construir + verificar en Studio | una llamada execute_luau |
Tiempo de máquina para una animación terminada en Studio: muy por debajo de un minuto. Lo que realmente cuesta tiempo son las iteraciones de autoría, así que inviértelas en la vista previa y nunca en el renderizado completo. Con references/pose-recipes.md para empezar, un segundo movimiento debería acertar en 1–3 vistas previas — el puñetazo y el saludo en references/ acertaron a la primera.
"report": true imprime la posición de cada articulación en cada pulso: cuando una pose se ve mal, nombra la articulación en una sola ejecución en lugar de cinco pasadas de renderizado adivinando.
No renderices para responder a una pregunta que una sonda puede responder.
No negociables
Cada uno está aquí porque saltárselo envió algo roto que tenía buen aspecto:
- Nunca confíes en una ejecución que salió con 0.
anim_render.pyafirma la integridad del rig por fotograma, afirma que los fotogramas se escribieron, y sale con no-cero en caso contrario. - Mira los fotogramas. Cada pasada.
- Con una referencia, construye la comparación lado a lado y juzga sobre ella — nunca solo en el renderizado.
- Inspecciona el GIF terminado en sí mismo, no los PNG de los que lo codificaste.
- Nunca relajes una tolerancia para que una luz roja se vuelva verde. Arregla la especificación.
Flujo de trabajo
1. Calibra el rig (cualquier rig que no hayas usado)
blender --background <rig>.blend --enable-autoexec --python scripts/calibrate_rig.py
blender --background <rig>.blend --enable-autoexec --python scripts/sweep_control.py -- FK_UpperLeg.R:rot TORSO:rot
calibrate_rig.py informa sobre la armadura de deformación vs control, la trampa de Acción, el estado del interruptor IK/FK, y qué controles realmente mueven algo. sweep_control.py da la dirección, signo y rango utilizable de cada eje — mide la dirección del hueso así como su posición, por lo que los controles solo de rotación no se pasan por alto.
Si los huesos FK_* se leen inertes, ese es el interruptor IK/FK, no un rig muerto.
2. Redacta la especificación
fps, duration, w, h, margin, views, properties, plain, preview, report, y keyframes[] de {t, ease, bones: {Bone: {rot|loc|target|aim}}}.
rot es lo que quieres casi siempre. loc para controles sin efector final (ROOT). target / aim son la vía de escape de IK — ver trampas 12–15.
Tres cosas que salen mal cada vez si las olvidas:
- Los ángulos hijo de FK se combinan con el padre. Hombro 50° + codo 70° coloca el antebrazo a 120° de la vertical, apuntando por encima del hombro. Mantén hombro + codo por debajo de ~110° para una guardia.
- La inclinación y giro van en
UpTorso, que solo impulsa la parte superior del cuerpo.TORSOimpulsa también las piernas, por lo que inclinarlo vuelca la figura y desliza el pie plantado. El rig también amplifica:X = +15balancea la cabeza 23°. - Contra-rota el tobillo de apoyo,
FK_Foot.X ≈ -(FK_UpperLeg.X + FK_LowerLeg.X), o el pie se inclina con la pierna y el personaje parece estar parado en una pendiente.
Consulta references/example-fk-roundhouse.json (patada de 0.8s) y references/example-fk-punch.json (cross de 0.5s), además de references/pose-recipes.md.
2a. SI HAY UN OBJETO EN LA MANO, INVESTIGA CÓMO SE SOSTIENE REALMENTE. PRIMERO.
Este paso ocurre ANTES de que redactes un fotograma clave, y no es opcional. En el momento en que un clip tiene un arma o herramienta, "¿la pose se lee?" deja de ser una pregunta sobre el rig y se convierte en una pregunta sobre ese objeto, que es un hecho sobre el mundo y no algo que inferir de una matriz.
El fallo que esto existe para prevenir, de una compilación real: una alabarda fue creada con su cabeza ABAJO a la cadera del portador. Cada etapa posterior hizo su trabajo perfectamente — el motor reprodujo el agarre creado, la tira de pose coincidió con la hoja de contacto fotograma por fotograma, error de agarre 0.000, cero muestras del arma dentro del cuerpo — y el juego envió un arma de asta llevada al revés. Una pose incorrecta creada aquí es invisible para todas las comprobaciones posteriores, porque cada comprobación posterior mide la concordancia con ESTO. Cuando un humano finalmente miró, el veredicto fue que estaba al revés. Tenían razón, y el costo fue una sesión completa aguas abajo de una decisión tomada en diez segundos aquí.
Antes de redactar:
- Busca cómo se lleva y usa la clase de arma. Fotografías de practicantes, no arte conceptual, no otros juegos. Diez segundos de lectura superan cuatro rondas adivinando números.
- Escribe la respuesta en la especificación como
_intent, como una oración sobre el arma: "cabeza arriba, asta cruzando el hombro delantero", "hoja angulada hacia arriba y adelante desde una mano baja". Esa oración es contra lo que se juzgará la hoja de contacto — ver paso 4. - Verifica las obvias de la lista de abajo antes de recurrir a una búsqueda.
| clase | en reposo | en un golpe |
|---|---|---|
| arma de asta, alabarda, naginata, lanza | cabeza ARRIBA — al hombro, con el extremo en el suelo, o en guardia con la hoja a la altura del pecho o superior. Nunca colgando a los pies | la cabeza lidera el arco; el asta cruza frente al cuerpo, nunca en el mismo plano vertical que el brazo |
| espada | angulada hacia arriba y adelante desde una mano baja, alrededor de +35 grados. Recta hacia abajo se lee como caída | el filo lidera; la muñeca no es una bisagra, todo el brazo lleva el arco |
| hacha, martillo | cabeza arriba o al hombro, el peso llevado alto | la cabeza es la masa — llega última y llega más fuerte |
| arma de puño, guantelete | se usa, no se agarra; guardia de boxeador, ambos puños arriba | las caderas lo impulsan, no el hombro |
Sostén el objeto en una pose en la que el propio cuerpo del portador podría meterse. Un transporte con una mano de cualquier cosa más larga que el personaje no se sienta en el mismo plano que el brazo, o se empalma.
3. Renderiza y verifica
blender --background <rig>.blend --enable-autoexec --python scripts/anim_render.py -- spec.json out/
ffmpeg -start_number 0 -i "out/side_%03d.png" -vf "scale=240:-1,tile=6x6" sheet.png
La cámara se encuadra sobre los límites de toda la animación y resuelve su distancia desde el campo de visión, por lo que nada sale del fotograma; margin (por defecto 1.10) es la única perilla. Renderiza al menos dos ángulos — una patada de pierna derecha es invisible desde la izquierda.
Luego juzga la hoja contra la REFERENCIA, no contra sí misma. Abre la oración _intent del paso 3a y verifica la hoja fotograma por fotograma contra ella: ¿está la cabeza arriba?, ¿lidera la hoja?, ¿cruza el asta frente al cuerpo? Una hoja de contacto solo prueba que el renderizado coincide con la especificación. No puede decirte que la especificación era correcta, y cada etapa posterior la tratará como verdad absoluta — así que este es el último punto en el pipeline donde una pose incorrecta es barata de arreglar. Si la hoja y la referencia discrepan, la referencia gana y la especificación cambia.
4. Entrega un GIF, luego verifica el GIF
ffmpeg -framerate 30 -start_number 0 -i "out/side_%03d.png" -framerate 30 -start_number 0 -i "out/tq_%03d.png" -filter_complex "[0]scale=420:-1[a];[1]scale=420:-1[b];[a][b]hstack=2,split[s0][s1];[s0]palettegen=stats_mode=diff[p];[s1][p]paletteuse=dither=bayer:bayer_scale=3" -loop 0 anim.gif
Lee la hoja UNA VEZ, al tamaño que necesites y no más grande. Una hoja de contacto es el objeto más caro en este pipeline: una imagen se reenvía en cada llamada de herramienta posterior en el mismo contexto, por lo que una lectura temprana de la hoja a resolución completa cuesta cientos de miles de tokens al final de una ejecución. Redúcela, recorta a la extremidad en cuestión cuando esa sea la pregunta, y no la vuelvas a abrir para re-verificar algo que podrías haber medido. Cuando una verificación puede ser un NÚMERO — ¿sale el arma de la mano?, ¿pasa a través de una extremidad?, ¿qué ángulo tiene? — conviértelo en un número y lee una línea de texto en su lugar.
Luego extrae fotogramas del GIF terminado y míralos — el movimiento se lee diferente de las imágenes fijas, y las configuraciones de codificación fallan silenciosamente:
ffmpeg -i anim.gif -vf "select='not(mod(n,2))',tile=4x3" -vsync 0 verify.png
Un clip creado rompe los que no creaste
El script Animate predeterminado de Roblox reproduce idle, caminar, correr, saltar, caer y trepar con prioridad Core. Cualquier cosa que crees y reproduzcas con prioridad Idle o superior los enmascara en cada articulación que posa, mientras dure la reproducción.
Por lo tanto, un bucle de idle de cuerpo completo — la solución correcta para que un personaje se pare con un arma — detiene el movimiento de las piernas cuando el jugador camina, porque tu clip está posando las piernas con una prioridad más alta que el ciclo de caminar. Se ve exactamente como "falta la animación de caminar", y aparece solo en el personaje para el que creaste el idle, lo que se lee como
...
[truncado para traducción]