← BibliotecaAnimaciónmormon/universal-animations
Clonar
fogon pieces add universal-animationsgit clone https://git.fogon.gg/mormon/universal-animations.gitfogon new universal-animations --from universal-animationshttps://fogon.gg/piece/42/animaciones-universalesAnimaciones universales
85 animaciones para personajes humanoides, de Quaternius (Universal Animation Library 1 y 2, dominio público, CC0), listas para three.js: caminar, trotar, correr, agacharse, saltar, rodar, deslizarse, nadar, sentarse, espada y escudo, pistola, magia, golpes, trabajos de granja, zombi. Todas sobre un mismo esqueleto de 65 huesos, así que sirven para cualquier personaje que lo tenga: los maniquíes que vienen acá, los Universal Base Characters y el resto de los personajes de Quaternius hechos con ese rig, o uno tuyo.

En la demo: elegí un clip de la lista (el buscador entiende walk, sword, espada, sentado…; ↑ ↓ recorren la lista). Abajo: pausa (espacio), la barra para ir a un momento, la velocidad, si se repite, Avanza (para los clips que se desplazan: el personaje camina por el piso en vez de quedarse en el lugar) y el cambio de maniquí. La línea de código de abajo es la que reproduce lo que estás viendo; un clic la copia. **Soltá un .glb sobre la página** y los clips se le aplican a tu personaje: te dice cuántos de los 65 huesos encontró.
Qué trae
| Clips | Qué hay | |
|---|---|---|
Pack 1 (ual1, 0,9 MB) | 43 | caminar, trotar, correr, agacharse, saltar, rodar, empujar, nadar, sentarse y manejar, bailar, hablar, pistola (apuntar, disparar, recargar), puños, espada, hechizo, recibir golpes y morir |
Pack 2 (ual2, 0,9 MB) | 42 | combos de espada, escudo, deslizarse, salto ninja, trepar 1 m, llevar algo, cosechar, sembrar, regar, talar, abrir un cofre, comer, hablar por teléfono, brazos cruzados, decir sí y no, zombi |
| Maniquíes | 2 | male (1,83 m; 0,16 MB) y female (1,81 m; 0,44 MB): el mismo esqueleto, pies en y = 0, mirando a +Z |
En total 2,4 MB. De los 85 clips, 31 están hechos para repetirse (su nombre termina en _Loop) y 27 se desplazan.
Cómo se usa en un juego
fogon pieces add universal-animations
Eso trae client/universal-animations/ (el código y el catálogo: unos pocos KB) y agrega three.js al package.json. Los archivos de animación no viajan con el juego: se cargan desde la demo publicada de esta pieza (https://play.fogon.page/universal-animations/animations/), que los sirve a cualquier juego de Fogón.
import * as THREE from "three";
import { loadAnimations, loadMannequin, createAnimator } from "./universal-animations/animations";
await loadAnimations(); // los dos packs, una vez. Solo el primero: loadAnimations("ual1")
const person = await loadMannequin(); // o loadMannequin("female")
scene.add(person);
const animator = createAnimator(person);
animator.play("Idle_Loop");
// Más tarde: cambia con una mezcla suave de 0,2 s. Los que no se repiten se quedan en su última pose…
animator.play("Walk_Loop");
// …o pasan a otro clip cuando terminan.
animator.play("Sword_Attack", { fade: 0.1, then: "Sword_Idle" });
// En cada cuadro, con los segundos desde el anterior:
animator.update(dt);
En un personaje tuyo
Cualquier modelo con el mismo esqueleto (mismos nombres de huesos) sirve. Cargalo como siempre y pasáselo a createAnimator, en su pose de reposo (recién cargado):
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { createAnimator, loadAnimations } from "./universal-animations/animations";
const [gltf] = await Promise.all([new GLTFLoader().loadAsync("hero.glb"), loadAnimations("ual1")]);
scene.add(gltf.scene);
const hero = createAnimator(gltf.scene);
console.log(hero.bones.size, "huesos encontrados; faltan:", hero.missing);
hero.play("Jog_Fwd_Loop");
- Los clips solo giran los huesos y mueven la cadera: cada cuerpo conserva sus proporciones (brazos, piernas, alto). El movimiento de la cadera se escala al alto de la cadera de tu modelo, para que los pies sigan en el piso (
hips: "scale", lo normal;"keep"lo deja como en el clip y"none"no mueve la cadera). - Los huesos se buscan por nombre, sin importar mayúsculas, con o sin algo adelante (
Armature|pelvis,rig:pelvis). Un prefijo pegado (hero_pelvis) se detecta solo, por el hueso que termina enpelvis; también se puede decir:createAnimator(model, { prefix: "hero_" }). Y si alguno se llama de otra forma:{ bone: (name) => (name === "Head" ? "cabeza" : undefined) }. - Si el modelo está hecho de varias partes con su propio esqueleto cada una (un cuerpo, un casco, un pelo), el animador mueve el primero y hace que los demás lo sigan.
- Que los huesos tengan otra pose de reposo no importa: los clips dicen el giro de los 65.
Avanzar por el piso (root motion)
Los clips son «en el lugar»: un Walk_Loop mueve las piernas y vos movés al personaje. Los 27 que en los packs se desplazan (CLIPS[name].root) también saben cuánto: con rootMotion: true el animador te da, en cada cuadro, lo que el personaje avanzó, para que los pasos coincidan con el piso.
animator.play("Roll", { rootMotion: true });
// en cada cuadro
animator.update(dt);
person.position.add(animator.motion.clone().applyQuaternion(person.quaternion));
animator.motion está en el espacio del modelo (+Z es su frente), en metros; si el modelo está escalado, multiplicalo también por su escala. Walk_Loop avanza 1,3 m por vuelta (0,98 m/s), Jog_Fwd_Loop 5 m (5,4 m/s), Sprint_Loop 5,5 m (8,25 m/s), Roll 5 m.
Con tu propio AnimationMixer
import { clip } from "./universal-animations/animations";
const walk = await clip("Walk_Loop"); // un THREE.AnimationClip
new THREE.AnimationMixer(person).clipAction(walk).play();
Sus pistas se llaman como los huesos (pelvis.position, spine_01.quaternion…): andan en cualquier modelo cuyos huesos tengan esos nombres exactos. clip(name, { rootMotion: true }) trae además la pista del hueso root desplazándose.
Lo que exporta animations.ts
loadAnimations(packs?, { base?, onProgress?, manager? }) | baja los clips de un pack ("ual1", "ual2") o de los dos. Llamarla de nuevo no baja nada |
loadMannequin(which = "male", { shadows? }) | una copia nueva del maniquí (Promise<Object3D>); comparten geometría y materiales |
createAnimator(model, { hips?, fade?, prefix?, bone? }) | el animador de un modelo: play, playAsync (baja el pack si falta), crossFade, stop, update(dt), current, action, motion, mixer, bones, missing, clipFor(name), dispose() |
play(name, { fade?, loop?, speed?, at?, rootMotion?, then? }) | fade: segundos de mezcla (0,2) · loop: por defecto, lo que dice el clip · speed: negativa lo pasa al revés · at: desde qué segundo · then: qué clip sigue cuando termina |
clip(name, { rootMotion? }) · clipNow(name) | el THREE.AnimationClip (el primero baja su pack si falta) |
CLIPS · clipNames({ pack?, group? }) · clipInfo(name) · isClip(text) | el catálogo, sin bajar nada: de cada clip, su pack, su grupo, cuánto dura, si se repite y por dónde se desplaza |
ClipName · BoneName · PackId · GroupId | los nombres como tipos: animator.play("Wlak_Loop") no compila |
GROUPS | los grupos con su nombre para mostrar (move: "Moverse"…) |
BONES · HIPS_HEIGHT · mapBones(model, { prefix?, bone? }) | los 65 huesos del esqueleto, el alto de la cadera del maniquí (0,917 m) y qué hueso de un modelo corresponde a cada uno |
setBase(url) · isLoaded(pack) · disposeAnimations() | de dónde se cargan los archivos (tu propia copia), si un pack ya está, liberar todo |
Los clips
→ se desplaza (sirve con rootMotion) · ² es del pack 2.
| Grupo | Clips | |
|---|---|---|
move Moverse | 20 | ClimbUp_1m→² · Crouch_Fwd_Loop→ · Crouch_Idle_Loop · Jog_Fwd_Loop→ · Jump_Land · Jump_Loop · Jump_Start · LayToIdle² · NinjaJump_Idle_Loop² · NinjaJump_Land² · NinjaJump_Start² · Push_Loop→ · Roll→ · Slide_Exit→² · Slide_Loop→² · Slide_Start→² · Sprint_Loop→ · Walk_Carry_Loop→² · Walk_Formal_Loop→ · Walk_Loop→ |
idle Quieto y gestos | 11 | Dance_Loop · Idle_FoldArms_Loop² · Idle_Lantern_Loop² · Idle_Loop · Idle_No_Loop² · Idle_Rail_Call² · Idle_Rail_Loop² · Idle_TalkingPhone_Loop² · Idle_Talking_Loop · Idle_Torch_Loop · Yes² |
interact Interactuar | 4 | Chest_Open² · Consume² · Interact · PickUp_Table |
sit Sentado | 5 | Driving_Loop · Sitting_Enter · Sitting_Exit · Sitting_Idle_Loop · Sitting_Talking_Loop |
work Trabajos | 5 | Farm_Harvest² · Farm_PlantSeed² · Farm_Watering² · Fixing_Kneeling · TreeChopping_Loop² |
melee Golpes y lanzar | 5 | Melee_Hook→² · Melee_Hook_Rec² · OverhandThrow² · Punch_Cross · Punch_Jab |
sword Espada | 11 | Sword_Attack→ · Sword_Block² · Sword_Dash→² · Sword_Heavy_Combo→² · Sword_Idle · Sword_Regular_A→² · Sword_Regular_A_Rec→² · Sword_Regular_B→² · Sword_Regular_B_Rec→² · Sword_Regular_C→² · Sword_Regular_Combo→² |
shield Escudo | 4 | Idle_Shield_Break² · Idle_Shield_Loop² · Shield_Dash→² · Shield_OneShot² |
pistol Pistola | 6 | Pistol_Aim_Down · Pistol_Aim_Neutral · Pistol_Aim_Up · Pistol_Idle_Loop · Pistol_Reload · Pistol_Shoot |
magic Magia | 4 | Spell_Simple_Enter · Spell_Simple_Exit · Spell_Simple_Idle_Loop · Spell_Simple_Shoot |
hit Recibir golpes | 4 | Death01→ · Hit_Chest · Hit_Head · Hit_Knockback→² |
swim Nadar | 2 | Swim_Fwd_Loop→ · Swim_Idle_Loop |
zombie Zombi | 3 | Zombie_Idle_Loop² · Zombie_Scratch² · Zombie_Walk_Fwd_Loop→² |
pose Pose | 1 | A_TPose |
Los que van en serie: Jump_Start → Jump_Loop → Jump_Land; Sitting_Enter → Sitting_Idle_Loop → Sitting_Exit; Spell_Simple_Enter → …_Idle_Loop → …_Shoot → …_Exit; Slide_Start → Slide_Loop → Slide_Exit; Sword_Regular_A → Sword_Regular_A_Rec (el golpe y su recuperación). Los tres Pistol_Aim_* son poses de 0,17 s para mezclar según hacia dónde se apunta.
El esqueleto
65 huesos, con los nombres del maniquí de Unreal. root está en el piso entre los pies; todo cuelga de pelvis.
root
└─ pelvis
├─ spine_01 ─ spine_02 ─ spine_03
│ ├─ neck_01 ─ Head
│ ├─ clavicle_l ─ upperarm_l ─ lowerarm_l ─ hand_l ─ (dedos)
│ └─ clavicle_r ─ upperarm_r ─ lowerarm_r ─ hand_r ─ (dedos)
├─ thigh_l ─ calf_l ─ foot_l ─ ball_l ─ ball_leaf_l
└─ thigh_r ─ calf_r ─ foot_r ─ ball_r ─ ball_leaf_r
Los dedos de cada mano (_l y _r): thumb, index, middle, ring y pinky, cada uno con _01, _02, _03 y la punta _04_leaf (por ejemplo index_02_l). Head va con mayúscula. La lista completa está en BONES.
Para poner algo en la mano: animator.bones.get("hand_r")!.add(sword).
Archivos
client/universal-animations/animations.ts | lo que se comparte: cargar, el animador, buscar los huesos |
client/universal-animations/catalog.ts | el catálogo de clips y huesos (lo genera tools/build.ts) |
client/main.ts · public/index.html | la demo: el visor |
public/animations/ | ual1.glb, ual2.glb (solo esqueleto y clips), mannequin.glb, mannequin_f.glb |
tools/build.ts | arma public/animations/ y el catálogo desde los packs originales |
Qué se les hizo a los archivos originales
Los .glb de los packs pesan 7,6 y 8,1 MB cada uno. tools/build.ts los deja en 2,4 MB entre todo, sin tocar el movimiento: saca las pistas que no dicen nada (la escala de cada hueso, que siempre es 1, y la posición de los huesos que nunca se mueven de su lugar: todos menos la cadera), quita los cuadros que una línea recta ya da (tolerancia de 0,0001) y comprime con meshopt (el decodificador viene con three.js). Los maniquíes van en archivos aparte. Los archivos _RM de los packs (los mismos clips con desplazamiento) solo difieren en la pista del hueso root: esa pista quedó guardada en el catálogo, en vez de una segunda copia de todo.
Para rehacerlos (con los packs «Standard» bajados de quaternius.com):
cd tools && bun install
bun build.ts "…/Universal Animation Library[Standard]" "…/Universal Animation Library 2[Standard]"
Límites
- Son las versiones gratuitas («Standard») de los packs: 43 clips cada una (la pose
A_TPoseestá en las dos). Las versiones pagas de Quaternius traen más; no están acá. - Sirven para modelos con este esqueleto. No hay retargeting a otros (Mixamo, VRM, Rigify): con otros nombres de huesos se puede mapear con
bone, pero si los huesos están orientados de otra forma las poses salen torcidas. - Las proporciones del cuerpo se respetan, pero un cuerpo muy distinto del maniquí (brazos mucho más cortos, hombros más anchos) puede atravesarse a sí mismo o no llegar a tocar lo que el clip toca.
- Los de nadar están hechos con la superficie del agua en y = 0: el cuerpo queda por debajo del piso.
- Los de espada, escudo, pistola, linterna y antorcha no traen el objeto: ponelo vos en
hand_rohand_l. - No hay capas ni máscaras (caminar con las piernas y apuntar con el torso a la vez): para eso, usá el
mixerdel animador oclip()con tu propioAnimationMixery filtrá las pistas por hueso. rootMotionda el desplazamiento del clip principal; durante la mezcla entre dos clips no se promedia.
Licencia y crédito
Las animaciones y los maniquíes son de Quaternius (quaternius.com), publicados como CC0 1.0: dominio público, sin obligación de dar crédito (pero se lo merece; también tiene Patreon). El código de esta pieza (el cargador, el animador, el visor y el script que achica los archivos) también es CC0.
Elegí un archivo.
| Versión | Cuándo | Peso | Commit |
|---|---|---|---|
| v1 en la demo | 12 de nov de 2026 | 3.2 MB | 5b87cc0 |
Todavía nadie publicó una versión hecha a partir de esta pieza.
Armá el pedido para tu agente
Elegí qué querés hacer, copiá el pedido y pegáselo a tu IA (Claude, ChatGPT, Codex…). Ella hace el resto.