Loading character
0%

Character creator — live 3D

Drag to orbit · scroll to zoom

loading…

Shape

Skin tone

Eye colour

Eyebrows

Eyelashes

Lip colour

Style

Colour

Facial hair

Style

Frame colour

Lens tint

Clothing

Tee colour

Flag

Emote / pose

What this proves

  • Clothing selection — each garment is its own skinned mesh sharing the body's skeleton, so selecting is just toggling visibility. Colour is a material value, which is how corps colours stay free.
  • One garment, every body type — switch body or build and the clothes refit. The variants are glTF morph targets, and the SAME proxy binding that fitted each garment generated a matching morph target on it. At runtime one influence value is set on the body and on every garment. No per-body art, and no per-body download.
  • Weight and frame are continuous — morph influences are floats, so the same targets that drove buttons now drive sliders, and every value between them is a valid body. The weight slider is signed: its sign picks which of two targets to drive, so lean and heavy are one control.
  • Height is a skeleton edit, not a morph — and it has to be. Morph targets are applied to the bind-pose vertices before skinning and never move the bones, so a height morph would leave the knee geometry somewhere the knee bone isn't: fine standing still, wrong the moment a clip bends the leg. Scaling each bone's local translation moves the joints apart instead, so limbs lengthen without thickening and the skull keeps its size. Clothing needs nothing — it is skinned to the same bones, so it follows exactly.
  • Not everything should be a proxy — glasses are rigid. Binding them to the body like clothing would shear the frame the moment a face preset widened the skull, so instead they hang off the head bone and carry no morph targets at all: one transform per morph target, six numbers each, solved in the exporter from how far the nose, temples and ears actually moved, and summed at runtime from the same influence values that drive the morphs. Ten styles for ~300 KB.
  • Emotes and reposing — glTF animation clips driving the shared 163-bone skeleton, crossfaded by three.js's AnimationMixer, holding the final pose. Orbit is free camera control on top.

Why three.js

It reads glTF natively — skinning, morph targets and animation clips all came across with no custom loader — and the same asset runs unchanged on the web and in React Native through expo-gl / expo-three, or in react-three-fiber if the app goes React. Babylon.js is the credible alternative and has better built-in tooling, but it's heavier and DutDut's frontend is vanilla JS with no build step, so three.js is the smaller commitment.

Honest limits

  • No subdivision here — this is the raw 13k-quad cage, so silhouettes are a little faceted next to the Blender renders. Add a subdivided export, or normal maps, when the art is final.
  • Body poke-through is possible with clothes hidden or on extreme morphs. The Blender pipeline solves it with an under-cloth mask; the runtime equivalent is an alpha mask texture on the body, per garment.
  • Body variants are a width profile, not real MakeHuman morph targets — those ship with the app, not the repo. A real one flows through identically.