The facade writes a math value component-wise, and an axis key is the domain identity ​
addBinding replaces object[key] for every scalar control. For a value the math dispatch matched it copies the committed axes onto the object already there instead, so a bound THREE.Vector3 keeps its identity, its methods, and any other reference an application holds to it. A caller who binds mesh.position gets a live Vector3 back from the change handler, not a plain record that has quietly replaced it.
That write leaves the property's identity unchanged, which the field's own hasChanged reads as no edit at all: ADR-0021 makes vector properties immutable snapshots compared component-wise, and the same object compares equal to itself. Binding.refresh() therefore assigns a fresh record built from the value's own numeric axes rather than the bound object.
Axes the bound object does not already carry are skipped, so binding a two-axis object never grows a z on it, and a Mixed axis is never written as a number.
Because writes go by axis name, the name has to be the truth. jolly-vector2 takes an axes pair, "xy", "xz" or "yz", and that key is what value holds, the glyph in the corner chip, the --jolly-axis-<key> colour and the data-axis scrub target. A field sizing a box across the ground plane reads as a red X and a blue Z, and hands back { x, z }. Switching axes on a mounted field moves each axis by position unless the new value already carries the new axes, so a template binding both together does not see its own value overwritten.
jolly-transform is left out of the dispatch. It is not a JollyField: it carries no label, disabled, align or path, and it owns three sub-fields that lock and revert independently, so one Binding cannot describe it. Three bindings, or the element directly, can.
Considered Options ​
- Replacing the property, as scalars do. Swaps a
THREE.Vector3for a plain object on the first edit, breaking every method call and every other reference to it. - An explicit
write: "assign" | "mutate"option. Every 3D caller wants the same answer, and the wrong default silently corrupts the bound object rather than failing. - Assigning the bound object back to the field on refresh. Component-wise
hasChangedsees the same object and never repaints. - Relabelling a
jolly-vector2while keeping keysxandy. The field would show Z while writingyonto an object carryingxandz. - A separate
jolly-vector2-xzelement. Three near-identical elements, registrations and API pages for one property's worth of difference.