← LibraryAssetmormon/universal-characters
Clone
fogon pieces add universal-charactersgit clone https://git.fogon.gg/mormon/universal-characters.gitfogon new universal-characters --from universal-charactershttps://fogon.gg/piece/41/personajes-base-universalesPersonajes base universales
Los Universal Base Characters de Quaternius listos para three.js: un hombre y una mujer (en ropa interior: para vestirlos, o para usarlos así), cinco peinados, cejas y barba, y colores para la piel, el pelo, los ojos y la ropa interior. Traen el esqueleto de 65 huesos de la Universal Animation Library: cualquier animación de esa biblioteca los mueve.

En la demo armás uno con los controles (o tocás uno ya armado, o «al azar»), elegís la animación, y abajo aparece la línea de código que lo crea: un clic y la copiás. «Varios» pone siete juntos.
Qué trae
- 2 cuerpos: hombre (1,81 m, 13.334 triángulos) y mujer (1,77 m, 13.580), con ojos aparte.
- 5 peinados: rapado (sin pelo), corto, con raya, largo y rodetes. Todos van en los dos cuerpos.
- Cejas (las de cada cuerpo) y barba.
- 9 pieles (pálida, clara, media, morena, marrón, oscura, y verde, azul y gris para orcos y otros), 8 colores de pelo, 5 de ojos, 7 de ropa interior. La piel, el pelo y la ropa interior aceptan también cualquier
"#rrggbb". - 12 animaciones de muestra (para que la demo se mueva y para empezar): quieto, hablando, caminar, trotar, correr, salto (arranque, en el aire, caída), bailar, un gesto con la mano, sentado y un golpe. Las demás van en la pieza
universal-animations. - Todo pesa ~2 MB: modelos 0,56 MB y animaciones 0,62 MB (comprimidos con meshopt), 16 texturas WebP 0,8 MB.
Usarlo en tu juego
fogon pieces add universal-characters
Eso trae client/universal-characters/characters.ts (solo código: los modelos se cargan de la demo publicada en https://play.fogon.page/universal-characters/characters/, que los sirve a cualquier juego). Necesita three.
import * as THREE from "three";
import { loadCharacters, createCharacter, randomLook } from "./universal-characters/characters";
await loadCharacters(); // una vez
const hero = createCharacter({ body: "female", skin: "tan", hair: "buns", hairColor: "black", eyes: "hazel", underwear: "red" });
scene.add(hero.object);
hero.play("Walk_Loop");
const stranger = createCharacter(randomLook());
stranger.object.position.set(2, 0, 0);
scene.add(stranger.object);
// en el bucle del juego, con los segundos desde el cuadro anterior:
hero.update(dt);
stranger.update(dt);
// una animación que se juega una vez y vuelve a esperar:
hero.play("Punch_Jab", { loop: false, onEnd: () => hero.play("Idle_Loop") });
// algo en la mano (va con el hueso):
hero.attach(sword, "hand_r");
Lo que exporta el módulo:
loadCharacters({ base?, clips?, onProgress?, manager?, anisotropy? }) | Carga el kit (una vez). clips: false no trae las animaciones de muestra. Devuelve un CharacterKit. |
createCharacter(look?, { clip? }) | Un personaje (lo que falte del look sale de DEFAULT_LOOK). Arranca con Idle_Loop; clip: null lo deja en su pose de reposo. |
Character | object (lo que va a la escena: mira a +Z, pies en y = 0), skeleton, bones (por nombre), bone(nombre), mixer, action, play(clip, { loop, fade, speed, from, fit, onEnd }), stop(), update(dt), attach(objeto, hueso = "hand_r"), clips, clip, look, body, pieces, triangles, height, dispose(). |
CharacterKit | create(look?, opciones?), clips (un Map por nombre), addClips(clips), fit(clip, cuerpo), catalog, base, dispose(). |
randomLook(rand?) | Un look al azar (con una función rand con semilla, siempre el mismo). |
BODIES, SKINS, HAIRS, HAIR_COLORS, EYES, UNDERWEAR | Las opciones, con su nombre en castellano para mostrar (y su color). |
DEFAULT_LOOK, fullLook(), BONES, DEFAULT_BASE | El look de partida, completar uno, los 65 huesos, de dónde se cargan los archivos. |
El look
| Campo | Valores |
|---|---|
body | "male", "female" |
skin | "pale", "light", "medium", "tan", "brown", "dark", "green", "blue", "grey" o "#rrggbb" |
hair | "none", "buzzed", "parted", "long", "buns" |
hairColor | "black", "brown", "blond", "red", "grey", "white", "pink", "blue" o "#rrggbb" (pelo, cejas y barba) |
eyebrows | true / false |
beard | true / false |
eyes | "brown", "hazel", "green", "blue", "grey" |
underwear | "black", "white", "red", "blue", "green", "yellow", "purple" o "#rrggbb" |
El color de piel es el que queda (no un tinte encima): la textura conserva su sombreado y toma el tono pedido. La ropa interior tiene su color aparte, así que cambiar la piel no la cambia.
Muchos personajes salen baratos: la geometría es de todos, y los materiales se arman una vez por color (una multitud con cinco tonos de piel tiene cinco materiales de piel). Lo propio de cada uno es su esqueleto y su mixer.
El esqueleto
65 huesos, los de la Universal Animation Library (los nombres de Unreal). Están en BONES, y en cada personaje en character.bones / character.bone("hand_r"):
- Tronco:
root,pelvis,spine_01,spine_02,spine_03,neck_01,Head(con mayúscula). - Brazos (
_ly_r):clavicle,upperarm,lowerarm,hand. - Dedos (
_ly_r):thumb,index,middle,ring,pinky, cada uno_01,_02,_03y_04_leaf(por ejemploindex_02_l,thumb_04_leaf_r). - Piernas (
_ly_r):thigh,calf,foot,ball,ball_leaf.
Sumarle las animaciones de universal-animations
Esta pieza trae doce animaciones de muestra. La biblioteca entera (pelea, armas, nadar, trepar, zombi…) está en la pieza universal-animations, hecha para este mismo esqueleto. Sus clips son THREE.AnimationClip con pistas por nombre de hueso (pelvis.quaternion, hand_r.quaternion…), así que entran directo:
import { loadAnimations, clipNames, clipNow } from "./universal-animations/animations"; // fogon pieces add universal-animations
const kit = await loadCharacters({ clips: false }); // sin las de muestra, si vas a traer las otras
await loadAnimations(); // los dos packs (o loadAnimations("ual1") para uno solo)
const clips: THREE.AnimationClip[] = clipNames().map((name) => clipNow(name));
// 1) dárselos al kit: desde ahí cualquier personaje los juega por nombre
kit.addClips(clips);
hero.play("Zombie_Idle_Loop");
// 2) o pasarle el clip a play()
hero.play(clips[0], { loop: false });
// 3) o usar el mixer a mano, como con cualquier modelo de three.js
hero.mixer.clipAction(clips[0]).play();
**La diferencia entre play() y el mixer a mano.** Las animaciones de la biblioteca están hechas sobre un maniquí cuyos huesos no miden lo mismo que los de estos cuerpos ni descansan en los mismos ángulos. Con mixer.clipAction(clip) el clip funciona tal cual viene, pero como mueve los 65 huesos (posición incluida), le da al cuerpo las proporciones del maniquí: hombros más anchos, la mujer igual de alta que el hombre. play() primero ajusta el clip al cuerpo (la misma pose con los huesos propios; se hace una vez por clip y por cuerpo y tarda unos milisegundos) y es lo que conviene usar. play(clip, { fit: false }) lo juega sin ajustar, y kit.fit(clip, "female") devuelve el clip ajustado para usarlo con tu propio mixer.
Usar los archivos sin internet
Los modelos y texturas están en public/characters/ de esta pieza (fogon pieces add trae solo el código). Copiá esa carpeta al public/ de tu juego y cargá desde ahí:
await loadCharacters({ base: "./characters/" });
| Archivo | |
|---|---|
characters.glb | Los dos cuerpos con su esqueleto y las ocho piezas de cabeza (meshopt). |
anims.glb | Las doce animaciones de muestra, sobre el esqueleto del maniquí, sin malla. |
catalog.json | Medidas de cuerpos y piezas, huesos, animaciones y la pose de reposo del maniquí (lo que usa el ajuste). |
textures/ | Piel (color, normal, y máscara de ropa interior + rugosidad), pelo (2 juegos), ojos (5 colores). |
tools/build.ts es el script que arma todo eso desde los dos zips de Quaternius (no se publica con la pieza; sus dependencias están en tools/package.json):
cd tools && bun install
bun build.ts "<carpeta de Universal Base Characters>" "<carpeta de Universal Animation Library>"
Cómo está hecho
- El pelo, las cejas y la barba. El pack los trae de dos maneras: «Origin at 0» (la malla suelta, en el origen) y «Rigged to Head Bone» (con el esqueleto, pesada entera al hueso
Head). Se usó la segunda: dice sobre qué cuerpo se modeló cada pieza y dónde va, y como cada vértice sigue a un solo hueso, se le saca el esqueleto y queda una malla común colgada del huesoHead: sigue a la cabeza en cualquier animación sin el costo de una malla con huesos. Para ponerla en el otro cuerpo se corre lo que difieren los dos cráneos (miden lo mismo; cambian unos milímetros de lugar). - Los colores. El pack trae la piel en dos versiones que solo cambian la ropa interior. De la diferencia sale una máscara: el material pinta la piel de un color y la ropa interior de otro. Los ojos de color son la textura original (marrón) con el iris repintado.
- Lo que no se cambió: las mallas, los pesos y las proporciones son los de Quaternius.
Límites
- Vienen en ropa interior y no hay ropa en esta pieza: es la base para vestir (lo que se agregue tiene que estar pesado a este mismo esqueleto) o para usar tal cual.
- Las cejas de cada cuerpo son las suyas (las de uno no calzan en la cara del otro), y la barba se modeló sobre el hombre: en la mujer queda en su lugar, pero es la misma barba.
- No hay huesos en la cara: los ojos y la boca no se mueven.
- Las animaciones no desplazan al personaje (sin «root motion»): para que camine, movés
object.positionvos (Walk_Loopanda bien a ~1 m/s). - En la biblioteca de animaciones no hay un saludo con la mano: la muestra trae
Interact(un gesto con la mano) eIdle_Talking_Loop. - Los colores de ojos son cinco, fijos (son texturas); la piel, el pelo y la ropa interior sí aceptan cualquier color.
Créditos y licencia
Modelos, texturas y animaciones de Quaternius: Universal Base Characters (cuerpos, peinados, cejas y barba) y Universal Animation Library (las doce animaciones de muestra). Todo es CC0: usalo como quieras, también en juegos comerciales, sin pedir permiso ni citar (aunque nombrar a Quaternius está lindo).
Pick a file.
| Version | When | Size | Commit |
|---|---|---|---|
| v1 in the demo | Nov 12, 2026 | 3.0 MB | a94cf29 |
Nobody has published a version made from this piece yet.
Put together the request for your agent
Pick what you want to do, copy the request and paste it into your AI (Claude, ChatGPT, Codex…). It does the rest.