Placing a piece's body
The instantiator gives a piece its body; features then decorate it. This is the
only module that knows how a mesh reaches a tosijs-3d scene, which is why
buildEnsemble takes it as an option — a test swaps it for a stub.
destroyable is a DECORATOR, and now it really is one
Most of what an ensemble describes — a lamp post, a rock, a ground plane, a whole standard demo scene — can never be shot, and giving it hit points is not a harmless default: terrain that quietly accumulates damage and vanishes at 100 000 is a worse outcome than terrain that was never a combatant.
For a while that forced an awkward shape. b3d-destroyable is the only element
that instantiates a library mesh BY NAME, and it had no way out of the combat
system, so either everything was a combatant or destruction had to CREATE the
body rather than decorate one. We placed plain pieces as raw library nodes to
dodge it, and destroyable had to register body: true.
tosijs-3d 0.7.2 added destroyable="off" (tosijs-3d#39, our ask), so that is
over. Every mesh piece is placed the same way and destroyable is a genuine
decorator: it contributes hit points to a body that already exists rather than
being the reason the body exists.
Rotation and scale go on the NODE; only position survives the element
b3d-destroyable's size is the placeholder cube's edge length and is
ignored when library is set — so for every piece with a real mesh, writing
it does nothing. Worse, the element forwards only {x, y, z, canonical} to
library.instantiate, so rx/ry/rz never reach the instance either.
Both measured before trusting anything: rendered width stayed 5.273 at scale
1, 2 and 4 alike, and an authored rot: [0, 45, 0] left the footprint at
3.63 × 3.63 — identical to no rotation. piece.scale and piece.rot were
documented fields that moved nothing, which is the worst kind of control there
is. Position is the exception and always worked, because the element rewrites
mesh.position from x/y/z every frame.
The element's own mesh — the library instance's root TransformNode — does
scale, and the element does not rewrite its scaling the way it rewrites
position. So scale is applied there, which also makes per-axis scale free.
Filed as tosijs-3d#47: a scale attribute belongs on the element, and then this
goes away.
The node does not exist yet when the element is appended. b3d-destroyable
instantiates inside lib.ready.then(...), so element.mesh is null for at
least a microtask after appendChild. Applying scale once, immediately, would
silently do nothing — the same failure as size, one layer down. whenMeshed
below is the retry, bounded so a piece that never instantiates cannot leave an
observer running forever.
Nothing to instantiate from? Draw a box.
Without a library — or with a mesh name the library does not have — the piece
becomes a b3d-box at the same spot. The ARRANGEMENT is most of what an author
is judging, so cubes in the right places beat an empty scene.