DEV Community

Cover image for We turned handmade art dolls into playable 3D characters in the browser
Like Art Doll World
Like Art Doll World

Posted on

We turned handmade art dolls into playable 3D characters in the browser

Like Art is a marketplace for handmade art dolls - a bit under 3,000 pieces from 700+ independent artists. Every one of them is a physical object: sculpted, sewn, painted and photographed by the person who made it.

A handmade art doll, photographed by its maker

We wanted to know what happens if that doll does not stop at the product page. So we built Doll World: a browser 3D world where the physical doll becomes a character that walks around, and where makers and collectors can meet, visit each other's rooms and play together.

Try it (free, no install, desktop + mobile): https://like-art.com/v6/game.html?world=1

Photo to character

  1. Photo selection. The maker's own photos. The character has to stay recognisable as that doll - face, hair, colours.
  2. Reconstruction. The doll is reconstructed into a canonical standing pose so it can be rigged and animated. Background, pose and lighting are normalised; the painted face and the hand-made details are preserved.
  3. Rig and animate. A small set of stock clips (idle, walk, run, sit, wave, dance).
  4. Quality gate. A doll does not reach the world unless the colour still matches the photo, the feet sit exactly on the ground plane, and there is no display stand or pedestal left in the mesh - the physical dolls are photographed on stands, so those have to be removed first.
  5. Install into the world as a floor-anchored GLB with LODs.

The same doll as a 3D character

Three things that were genuinely hard

1. Not every doll can be rigged (yet)

Automatic humanoid rigging assumes... a humanoid. Four-legged dolls (collectors own plush rabbits and bears) came back with HTTP 422 - pose estimation failed. Rather than block the whole production line, we parked the quadrupeds and are building a local Blender/Rigify path for them. Ship what works, park what does not.

2. One texture was 86% of a 22MB asset

A single 4096px WebP texture was 86% of the mobile asset size - the mesh was never the problem. We now keep the high-res texture on demand and generate LODs (1024-2048) for the world build with KTX2/Basis compression. A doll standing in the world is 2-3MB. We deliberately did not trade away polygons or final texture resolution to get there.

3. First load was 98.7MB

Game portals have hard budgets (CrazyGames wants the initial load under 50MB, and it measures the whole URL). The high-res ASTC texture layer alone was 57MB. Instead of degrading the main world, we added a build flag so the portal entry simply skips that layer:

// world-astc-32.js
function installWorldAstc32() {
  if (globalThis.__V6_LITE__ === true) return null; // lite build: skip the 57MB ASTC layer
  // ... normal path
}
Enter fullscreen mode Exit fullscreen mode

98.7MB to 41.7MB for the portal build, main world untouched and still 98.7MB.

Where it runs

The loop only works if the character still looks like your doll, so feedback from doll makers is genuinely welcome - especially if you spot a piece that came out of the pipeline looking wrong. Happy to go deeper on the rigging or the mesh pipeline in the comments.

Top comments (1)

Collapse
 
koda2026 profile image
Harun - solo dev •

"ship what works, park what does not" is the best engineering mantra i've read all week. trying to force a humanoid rig onto a plush rabbit is exactly how projects get delayed by months.

but the 98.7mb to 41.7mb portal build trick is pure genius. using a global __V6_LITE__ flag to strip the 57mb astc texture layer just to pass the crazygames budget, while keeping the main world untouched, is exactly the kind of pragmatic constraint-solving i love. i build a mobile-first ai app where the entire frontend bundle has to stay under 92kb for 3g networks, so watching you wrestle with 3d asset budgets and ktx2/basis compression is incredibly inspiring.

curious about the quality gate though: how are you automating the check for "feet sit exactly on the ground plane" and "no display stand left in the mesh"? is that a computer vision pass on the reconstructed mesh, or a heuristic based on the bounding box bottom?

massive respect for the lod pipeline. keeping the polygons and final resolution intact while optimizing the delivery is god-tier 3d webdev. 🐯