Writing a transform

An ensemble's pieces have two kinds of body and they are written to differently. Getting this wrong does not error — it silently does nothing, which is the worst failure mode a manipulator can have.

body write to why
an ELEMENT (b3d-destroyable) el.x/y/z, el.rx/ry/rz the element OWNS its transform: render() writes mesh.position from those attributes, so a write straight to the mesh is undone the next time anything re-renders
a NODE (a plain library instance) node.position / rotation / scaling nothing manages it, so the node IS the truth

Scale is the exception, and size is a trap

b3d-destroyable's size is documented as the placeholder cube edge length, ignored when library is set — so writing it does nothing for any piece with a real mesh, which is every mesh piece we place. Measured before relying on it: a piece's rendered width was 5.273 at scale: 1, 2 and 4 alike, with the root node's scaling sitting at 1,1,1 throughout. piece.scale was inert, and the editor's scale control was moving a number nothing read.

What DOES work is the element's own node. element.mesh is the library instance's root TransformNode, the element manages its position and rotation but not its scaling, and a write there survives: setting 2, 1.5, 3 held across frames and took the width from 5.273 to 10.546. So scale goes to the node in both branches, and per-axis comes free — filed upstream as tosijs-3d#47, since a scale attribute belongs on the element.

rx/ry/rz are degrees on an element (yaw/pitch/roll are aliases for ry/rx/rz), matching the format. Babylon nodes are radians, so the node path converts.

The quaternion trap, on our side of the fence

A TransformNode ignores .rotation while it has a rotationQuaternion — and the glTF loader always sets one. That is exactly the bug that made library.instantiate()'s rotation silently inert until tosijs-3d 0.7.0: it wrote .rotation, the quaternion won, and every value produced the model's baked orientation. position worked, which is what made it look wired up.

So rotating a node here clears the quaternion first. Skip that and a rotation drag moves nothing, with no error anywhere.