Animating your model
Use named nodes and sockets to move parts without touching child-array indices.
Named access beats indices
Every mesh in the factory is registered in root.userData.sculptRuntime.nodes under its part name, and attachment points are exposed under sculptRuntime.sockets. This is the contract your animation code should depend on.
Reaching into model.children[3] couples your code to the order the spec happened to emit. Re-run the reconstruction, or edit the spec, and that index can point at a different part. runtime.nodes.lid always means the lid.
Rotate and lerp a part
Each node is a normal THREE.Object3D, so you animate it by writing to its position, rotation, quaternion or scale. For anything that should ease rather than snap, lerp or damp toward a target every frame instead of assigning the final value directly.
A frame-rate-independent damp keeps motion consistent across devices: move a fraction of the remaining distance scaled by delta rather than a fixed step per frame.
const runtime = model.userData.sculptRuntime;
const OPEN = Math.PI * -0.4;
function tick(delta, isOpen) {
const lid = runtime.nodes.lid;
const target = isOpen ? OPEN : 0;
lid.rotation.x += (target - lid.rotation.x) * (1 - Math.exp(-8 * delta));
}Attach to a socket
Sockets are empty transform nodes placed at meaningful points — a hand, a muzzle, a mount. Because they live in the same scene graph, THREE.Object3D.attach lets you parent another object to a socket while preserving its current world transform.
This is how you equip a prop or pin an effect to a moving part: attach once, and the child inherits the socket's animation for free.
const runtime = model.userData.sculptRuntime;
runtime.sockets.handR.attach(sword);
// sword now follows the hand as it animates