Scaling safely
animsmith scale is an evidence-emitting producer for two different scale
operations. glTF/GLB supports both; the narrow FBX boundary supports only
rest/bind and always emits a new GLB. Neither operation guesses units or scale
policy from geometry, names, or asset categories.
Use the CLI reference for the exact command grammar and machine-readable output for the scale-evidence v4/v5 schemas. This guide owns the operator workflow and the boundary between the two operations.
Choose the operation
| Operation | Use it when… | Physical result |
|---|---|---|
whole-document | The entire source uses the wrong linear unit. | Every represented length changes by the declared factor. |
rest-bind | World geometry is already correct, but one skinned hierarchy carries a compensating inherited uniform scale. | World joint translations and orientations, sampled trajectories, and skinned geometry are preserved while the hierarchy is reparameterized to remove the composed scale. |
These operations are not interchangeable. A rest/bind cleanup must not be selected merely because a character appears too large or small, and a unit conversion must not be used to remove an inherited scale from one hierarchy.
Whole-document conversion takes one finite positive --factor. Rest/bind
requires all three declarations: a raw source-skin index, a raw source-root
node index, and the finite positive factor expected at that root. Use
animsmith measure source.glb to list authored source-node and source-skin
indices; neither selector is a normalized bone id or mesh-instance ordinal.
animsmith scale whole-document source.glb -o metres.glb \
--factor 0.01 --evidence metres.scale.json
animsmith scale rest-bind source.glb -o canonical.glb \
--source-skin-index 0 --source-root-node-index 3 \
--expected-factor 0.01 --evidence canonical.scale.json
There is no in-place mode, plan file, animsmith.toml key, implicit first
skin/root, or per-run tolerance override. Input, artifact, and evidence paths
must be three distinct files. For narrow FBX rest-bind, neither destination
may name a safe dependency key retained by the same-load closure, and a
symlink-refused dependency or terminal closure-budget stop prevents
publication. glTF/GLB artifacts keep the input container; narrow FBX
rest-bind emits a new .glb.
What one run proves
One invocation performs one ordered transaction:
- Parse the source and build a complete capability inventory.
- Compile one format-neutral
ScalePlancontaining the exact topology, payload shape, field ownership, and proof claims for that source. - For glTF/GLB, apply that plan directly to source JSON and buffer bytes; the
normalized model writer is not used. Narrow FBX
rest-bindfirst writes a private normalized GLB, then applies the plan and proof to that GLB. - Reload the exact emitted bytes and run the independent normalized core proof plus the raw artifact proof. The artifact proof also reruns the writer and requires deterministic bytes.
- Stage the artifact/evidence pair, read the staged artifact back, and require its digest to match the bytes that were proved before promoting both files.
A reported refusal publishes neither file and restores any prior pair. The two destinations require two renames, so a process killed between them has the crash window documented in machine-readable output. Proof is not run again after staging: digest equality binds the already-proved bytes to the published file.
The current fixed tolerance identity is appendix-d-v6. It is recorded in
scale evidence together with each evaluated residual and both observed-factor
witness fields. Rest/bind derives those witnesses independently from the raw
source projection and normalized skeleton; whole-document conversion records
the declared factor in both because that operation has no source factor to
measure. There is no runtime alias for an older policy and no per-run tolerance
knob.
Write sets and preservation
Whole-document conversion rewrites represented lengths: node TRS translations
and matrix translation columns, mesh POSITION, translation animation values
and cubic tangents, raw glTF morph-target POSITION deltas, inverse-bind
translation columns, and corresponding accessor bounds. Rotation, scale,
normals, UVs, static and animated morph weights, key times, and other
dimensionless payloads remain outside the write set. Static JSON morph weights
retain their numeric values; animated weight accessor payloads remain
byte-exact.
Rest/bind reparameterization derives every multiplier from the selected raw topology. It rewrites the necessary node-local translation/scale or matrix components, translation and scale animation payload, and affected inverse binds. Mesh positions and the already-correct world geometry remain unchanged.
At factor one, whole-document conversion plans no semantic writes. See the
scale output contract for the exact artifact-preservation
and evidence-field semantics at that boundary.
Supported source boundary
Scale accepts self-contained glTF/GLB for both operations. A .gltf source with an
external buffer or image is refused rather than partially converted. Raw
preflight also refuses any source domain the current model and artifact proof
cannot preserve completely. Whole-document conversion admits only raw glTF
POSITION morph-target deltas with dimensionless static/animated weights;
NORMAL, TANGENT, sparse/interleaved scale-bearing accessors, unsafe aliases,
and every morph payload under rest/bind reparameterization remain refused.
It also refuses cameras and lights, along with GPU instancing, unregistered
extensions, extras, non-triangle primitives, secondary skin-influence sets,
unsafe accessor layouts, and animation targeting a matrix-authored node. The
rejection record contains the complete typed violation inventory.
Do not read the core model's static unprojected-connector rows as a current glTF capability. The glTF loader projects every accepted node today, and the raw writer has no connector-bridge implementation; that path is outside the supported source boundary.
With the default FBX feature, scale rest-bind source.fbx -o canonical.glb
accepts only the inventory-complete normalized subset. It requires the same
explicit skin/root/factor declarations, stages a private normalized GLB,
maps both selectors by exact unique named identity, then uses the existing raw
GLB rewrite/reload/proof path. The same-load gate admits exact marker,
LOD-group, stereo-camera, camera-switcher, and display-layer typed lists
because none can supply rest/bind state to that bridge, plus
shader/binding-table metadata. Display layers contribute only node membership
and editor visibility/freeze/color state; they do not alter projected nodes. It
admits a BindPose only when it covers every joint of each skin it touches and
its converted rows are finite, unambiguous, and agree with the converted
cluster bind or node rest-world matrix already consumed by the bridge; a
source without a Pose remains valid. The raw aggregate still counts all
admitted rows. Residual unmodeled typed lists fail closed with exact nonzero
kind counts. The same-load gate may also admit enumerated scale-invariant
conversion fidelity—omitted authored vertex/face/edge metadata, influence
projection with complete effective coverage, triangulation, and exact-bit
welding—without removing any inventory evidence. Missing influence coverage,
omitted point/line or mesh geometry, unsupported skinning/deformers, incomplete
binds or normals, and unclassified payload remain blockers. It
records the full FBX inventory and staged GLB digest in scale-evidence v5. The
published artifact is a re-encoded GLB: no raw FBX byte, object-property,
marker/camera/display-layer behavior, or authored-curve-key preservation is
claimed. FBX whole-document conversion remains refused. Character assembly
likewise does not silently apply either scale operation. Its existing bind-pose
canonicalization remains a distinct, explicit recipe operation.
Morph support intentionally remains a raw glTF whole-document capability; it
does not add morphs to the shared normalized model or enable rest/bind morph
reparameterization.
Outcomes and evidence
The CLI reference owns exit-status semantics, and the
output reference owns the scale-evidence v4/v5 wire contract
and publication outcomes. In brief, --format json prints the same record that
a successful run writes to --evidence; a refused run prints its rejection
record but never writes the evidence destination because there is no
artifact/evidence pair to publish.
The record carries no timestamp; declared paths remain as entered, and
identical inputs and arguments produce byte-identical evidence.
Embedding the same contract
Rust pipelines use animsmith_core::scale for planning and normalized proof,
and animsmith-gltf for raw preflight, exact-source rewrite, reload, and
artifact proof. Pass one compiled plan through rewrite_scale_plan; do not
substitute the fixture-only analytic reference builder for a format writer.
See the embedding guide and the
crate rustdoc for exact type and error contracts. Appendix D in
DESIGN.md
is the normative algebra and preservation decision; the
calibration notes record how the fixed proof policy is
measured.