A second geometry path
Meshes are drawn alongside sprites, not instead of them: their own vertex buffers, their own shader and their own pass with a depth buffer. The camera learned a perspective projection next to the orthographic one, and the scene view in the editor switched to an orbit camera with a ground grid, a ray picker and a transform gizmo working on real matrices.
Eight primitives come with it — cube, sphere, capsule, cylinder, plane, quad, plus a cone and a torus — so a scene can be put together before any model is imported. Lighting is deliberately minimal for now: unlit or a single directional light.
Models: GLB and glTF
GLB/glTF is the format the engine reads natively. Everything else — FBX, OBJ, DAE, STL, PLY, ABC, USD, BLEND — is converted to GLB by Blender in headless CLI mode, and from there it goes through the same pipeline. One importer for every format, at the cost of one external dependency: without Blender those formats are not imported, and the editor says so instead of quietly doing nothing.
The import bakes a binary asset of its own. One model is one file: all of its meshes and the node hierarchy with their transforms, so wheels and doors keep their own pivots. Drag it into the hierarchy and it unfolds into objects. Geometry compression is a project-level switch — meshopt, whose decoder weighs 4.7 KB in the wasm.
Skeleton, skinning, animator
A skinned character comes in from the same file: the skeleton and the clips ride inside the model, and a bone track is simply a third kind of track inside the animation clip the engine already had. That is the point of it — there is no separate 3D animation system.
So the animator is the one you already know from 2D. A graph of states, parameters of four types (float, int, bool, trigger), transitions with conditions on them — greater, less, equal, not equal, set or not set — exit time, and a crossfade duration per transition. The same controller asset, the same editor tab.
A 2D game pays nothing for it
All of it is behind two build switches. Turning 3D meshes off drops the meshes, the models, the primitives, the skinning, the mesh pass and both 3D shaders out of the web build; skinning has a switch of its own for a project that only needs static props. A 2D game keeps the wasm it had.