Expand description
Engine-agnostic animation linting primitives for Rust pipelines.
This crate is the embedding boundary for animsmith. It owns the core
data model (Document, Skeleton, Clip, Track), rig-role
resolution (detect_profile, ResolvedRoles::from_names),
typed configuration (Config), measurement generation
(measure::measure_document), versioned result envelopes
(contract::MeasureEnvelope, contract::LintEnvelope), measurement diffs
(diff::diff_measurements), structured findings (Finding), and
check execution (CheckCtx, all_checks, evaluate_checks).
The source_facts module owns the bounded, format-neutral V1 vocabulary
that format loaders bind to the exact primary bytes in an immutable
LoadedSource. A mutable normalized Document does not reconstruct
importer-sensitive source declarations; consuming the wrapper as a document
deliberately discards those facts. The separate dependency_closure
sidecar records bounded, same-load primary/external content identities over
the raw resource-declaration domain; format crates own rooted I/O while core
owns its validated value and canonical digest contract. The borrowing facts
view reuses the canonical model::SourceSkeletonAssets table and remains
separate from scale’s operation-specific capability and proof ledgers.
The opt-in bake_static_mesh_transforms operation canonicalizes supported
unanimated, unskinned mesh scenes into identity-root geometry and returns
deterministic producer evidence.
The opt-in transform::prune_constant_tracks helper removes only
interpolation-aware constant-track candidates whose sampled local and
model-space pose evidence remains within its documented tolerances.
The scale module owns the format-neutral plan/proof contracts for the
two distinct DESIGN.md Appendix D scale operations —
scale::ScaleOperation::WholeDocumentLinearUnits and
scale::ScaleOperation::RestBindUniformScale — through pure, fail-closed
scale::plan_scale and independent scale::prove_scale. A format
frontend owns exact source rewriting and hands the reloaded emitted
document back through scale::ScaleCandidate::from_document; core does
not expose a production candidate builder, decide selectors, publish
artifacts, or write files.
The animsmith-gltf and animsmith-fbx loader crates translate file
formats into this model; their docs.rs pages continue the library path for
format-specific loading and, for glTF, writing.
The embedding guide explains crate selection and integration boundaries. The pipeline scenario guide shows where an embedded gate fits in marketplace intake, mocap cleanup, outsourced acceptance, and CI. A runnable example exercises the complete library flow.
§Quick start
After a format crate has loaded a Document, resolve rig roles, build
a Config from the host pipeline’s contract, and share one
MetricGrids between measurements, checks, and optional report
generation:
use animsmith_core::{
CheckCtx, CheckSelection, Config, Document, MetricGrids, all_checks,
evaluate_checks, resolve_configured_roles,
};
use animsmith_core::measure::measure_document;
let doc = Document::default();
let config = Config::default();
config.validate()?;
let roles = resolve_configured_roles(&doc.skeleton, &config.rig);
let grids = MetricGrids::new(&doc);
let measurements = measure_document(&grids, &roles, &config);
let ctx = CheckCtx::new(&grids, &roles, &config);
let results = evaluate_checks(&ctx, &all_checks(), CheckSelection::All)?;
assert!(measurements.is_empty());
assert!(results.iter().all(|result| result.findings().is_empty()));CheckCtx::new consumes already-resolved roles; it does not interpret
Config::rig automatically. Frontends may use detect_profile,
resolve_configured_roles for the same named-profile plus inline-override
policy as the CLI. Missing prerequisites are represented as typed coverage
gaps rather than false findings.
§API status
The Rust API is pre-1.0 and may still change before the first stable
release. The intended extension points are the data model,
configuration types, measurement and diff APIs, rig-profile APIs, the
Check trait for custom checks, and the check catalog functions
re-exported from this crate root. Built-in check ids, CLI exit-code
semantics, and the shared versioned JSON envelope/schema ids are treated
as the most stable automation contracts. The contract module owns the
same envelope types and immutable identities for CLI and embedded
producers. The scene-asset
structs in model and the pipeline-mechanical helpers in
transform and static_bake are public so the loader, writer, and CLI crates can
share the same model, but they are less settled than the
measurement/check embedding flow while the crate is pre-1.0. Metric
formulas and individual Rust symbols are still subject to pre-1.0
refinement.
Public APIs that return Result document their # Errors cases.
Index-based accessors and transform helpers that rely on
loader-established invariants document their # Panics contracts.
Loader-valid documents from the format crates should flow through
checking, sampling, and measurement without panicking on untrusted
input.
Re-exports§
pub use check::Check;pub use check::CheckCtx;pub use check::all_checks;pub use check::mechanical_checks;pub use config::ClipExpectations;pub use config::Config;pub use config::ConfigValidationError;pub use config::GaitGroup;pub use config::MovementOwner;pub use config::Pinned;pub use config::RuntimeNodeSelectorResolution;pub use config::RuntimeNodeSelectors;pub use config::RuntimeNodesConfig;pub use config::SeveritySetting;pub use config::SyncGroup;pub use config::TimeComplementSettings;pub use contract::DiffEnvelope;pub use contract::InputIdentity;pub use contract::LintEnvelope;pub use contract::LintFileReport;pub use contract::MEASUREMENTS_SCHEMA_ID;pub use contract::MEASUREMENTS_SCHEMA_VERSION;pub use contract::MeasureEnvelope;pub use contract::MeasureFileReport;pub use contract::MeasurementContract;pub use contract::MeasurementContractError;pub use contract::MeasurementFileError;pub use contract::MeasurementReportError;pub use contract::MeasurementReportFile;pub use contract::MeasurementReportInput;pub use contract::MeasurementReportReadError;pub use contract::OUTPUT_SCHEMA_ID;pub use contract::OUTPUT_SCHEMA_VERSION;pub use contract::OUTPUT_V10_MAX_CHECKS_PER_FILE;pub use contract::OUTPUT_V10_MAX_FILES;pub use contract::OUTPUT_V10_MAX_REPORT_BYTES;pub use contract::OutputContractError;pub use contract::RigInfo;pub use contract::RigInfoError;pub use contract::ToolInfo;pub use contract::ToolSource;pub use contract::sha256_hex;pub use dependency_closure::DEPENDENCY_CLOSURE_BUDGET_V1_ID;pub use dependency_closure::DEPENDENCY_CLOSURE_V1_ID;pub use dependency_closure::DEPENDENCY_CLOSURE_V1_MAX_DEDUP_PROBES;pub use dependency_closure::DEPENDENCY_CLOSURE_V1_MAX_EXTERNAL_RESOURCES;pub use dependency_closure::DEPENDENCY_CLOSURE_V1_MAX_KEY_BYTES;pub use dependency_closure::DEPENDENCY_CLOSURE_V1_MAX_NORMALIZATION_BYTES;pub use dependency_closure::DEPENDENCY_CLOSURE_V1_MAX_PATH_COMPONENTS;pub use dependency_closure::DEPENDENCY_CLOSURE_V1_MAX_REFERENCES;pub use dependency_closure::DEPENDENCY_CLOSURE_V1_MAX_RESOURCE_BYTES;pub use dependency_closure::DEPENDENCY_CLOSURE_V1_MAX_TOTAL_RESOURCE_BYTES;pub use dependency_closure::DependencyClosureBuilderV1;pub use dependency_closure::DependencyClosureCoverageReasonV1;pub use dependency_closure::DependencyClosureCoverageV1;pub use dependency_closure::DependencyClosureError;pub use dependency_closure::DependencyClosureIdentityV1;pub use dependency_closure::DependencyClosureReferenceV1;pub use dependency_closure::DependencyClosureV1;pub use dependency_closure::DependencyClosureWorkV1;pub use dependency_closure::DependencyReferenceTargetV1;pub use dependency_closure::DependencyResourceKeyV1;pub use dependency_closure::DependencyResourcePurposeV1;pub use dependency_closure::DependencyResourceRefusalReasonV1;pub use dependency_closure::ExternalResourceIdentityV1;pub use dependency_closure::ResourceClosureBudgetV1;pub use dependency_closure::ResourceKeySyntaxV1;pub use engine_contract::ENGINE_CONTRACT_V1_MAX_AGGREGATE_ROWS;pub use engine_contract::ENGINE_CONTRACT_V1_MAX_COLLECTION_ROWS;pub use engine_contract::ENGINE_CONTRACT_V1_MAX_TEXT_BYTES;pub use engine_contract::ENGINE_CONTRACT_V1_MAX_TOTAL_TEXT_BYTES;pub use engine_contract::ENGINE_PROFILE_FACTS_V1_ID;pub use engine_contract::EngineAnimationAddressabilityV1;pub use engine_contract::EngineBakeOrExtractV1;pub use engine_contract::EngineClipSettingsV1;pub use engine_contract::EngineContractError;pub use engine_contract::EngineConversionControlV1;pub use engine_contract::EngineCoordinateBasisV1;pub use engine_contract::EngineDefaultStatusV1;pub use engine_contract::EngineFactIdV1;pub use engine_contract::EngineFactStateV1;pub use engine_contract::EngineFactValueV1;pub use engine_contract::EngineForwardAxisV1;pub use engine_contract::EngineHandednessV1;pub use engine_contract::EngineImportHandlingV1;pub use engine_contract::EngineLinearUnitV1;pub use engine_contract::EnginePrimarySourceV1;pub use engine_contract::EngineProfileFactV1;pub use engine_contract::EngineProfileSelectionV1;pub use engine_contract::EngineRootMotionAddressabilityV1;pub use engine_contract::EngineSettingApplicabilityV1;pub use engine_contract::EngineSettingDescriptorV1;pub use engine_contract::EngineSettingDomainV1;pub use engine_contract::EngineSettingIdV1;pub use engine_contract::EngineSettingRowV1;pub use engine_contract::EngineSettingScopeV1;pub use engine_contract::EngineSettingValueV1;pub use engine_contract::EngineTargetAddressabilityV1;pub use engine_contract::EngineUpAxisV1;pub use engine_contract::RESOLVED_ENGINE_SETTINGS_V1_ID;pub use engine_contract::ResolvedEngineProfileV1;pub use engine_contract::ResolvedEngineSettingsV1;pub use evaluation::Applicability;pub use evaluation::BUILTIN_COVERAGE_GAP_CODES;pub use evaluation::BUILTIN_EVALUATION_SCOPE_CODES;pub use evaluation::CheckEvaluation;pub use evaluation::CheckOutput;pub use evaluation::CheckSelection;pub use evaluation::ConfigurationState;pub use evaluation::CoverageGap;pub use evaluation::CoverageGapCode;pub use evaluation::EvaluationError;pub use evaluation::EvaluationScope;pub use evaluation::EvaluationScopeCode;pub use evaluation::EvaluationState;pub use evaluation::SelectionState;pub use evaluation::evaluate_checks;pub use evaluation::lint_requires_failure;pub use finding::Finding;pub use finding::MemberMeasurement;pub use finding::Severity;pub use finding::Value;pub use metrics::MetricGrids;pub use model::AdditionalInfluenceSet;pub use model::AffineDomainViolation;pub use model::Bone;pub use model::BoneId;pub use model::Clip;pub use model::DecodedImageColorType;pub use model::Document;pub use model::DocumentShapeError;pub use model::ImageContainerFormat;pub use model::ImageSourceKind;pub use model::Interpolation;pub use model::MaterialResourceAssets;pub use model::MaterialResourceCoverage;pub use model::MaterialTextureSlot;pub use model::MeshInstanceShapeViolation;pub use model::Property;pub use model::Skeleton;pub use model::SourceImageAsset;pub use model::SourceImageInspection;pub use model::SourceInfo;pub use model::SourceInverseBindAccessor;pub use model::SourceInverseBindAccessorStatus;pub use model::SourceMaterialAsset;pub use model::SourceMaterialTextureBinding;pub use model::SourceNodeAsset;pub use model::SourceNodeLocalRest;pub use model::SourceProjectionViolation;pub use model::SourceSkeletonAssets;pub use model::SourceSkeletonCoverage;pub use model::SourceSkinAsset;pub use model::SourceSkinAttachment;pub use model::SourceTextureAsset;pub use model::Track;pub use model::TrackShapeViolation;pub use model::TrackValues;pub use model::Transform;pub use model::validate_document_shape;pub use prediction::ENGINE_PREDICTION_V1_ID;pub use prediction::EnginePredictionBasisV1;pub use prediction::EnginePredictionFacetStateV1;pub use prediction::EnginePredictionFacetV1;pub use prediction::EnginePredictionV1;pub use prediction::FinitePredictionNumberV1;pub use prediction::MeasurementPointerV1;pub use prediction::PREDICTION_PROVENANCE_V1_ID;pub use prediction::PREDICTION_V1_MAX_AGGREGATE_PROVENANCE_ROWS;pub use prediction::PREDICTION_V1_MAX_BASIS_REFERENCES_PER_FACET;pub use prediction::PREDICTION_V1_MAX_BASIS_REFERENCES_PER_FILE;pub use prediction::PREDICTION_V1_MAX_FACETS_PER_FILE;pub use prediction::PREDICTION_V1_MAX_MEASUREMENT_POINTER_COMPONENTS;pub use prediction::PREDICTION_V1_MAX_REASONS_PER_FACET;pub use prediction::PREDICTION_V1_MAX_TEXT_BYTES;pub use prediction::PREDICTION_V1_MAX_TOTAL_TEXT_BYTES_PER_FILE;pub use prediction::PredictionBasisIdentityV1;pub use prediction::PredictionBasisReferenceV1;pub use prediction::PredictionContractError;pub use prediction::PredictionProvenanceIdentityV1;pub use prediction::PredictionProvenanceV1;pub use prediction::PredictionScalarV1;pub use prediction::RawSourceAxisV1;pub use prediction::RawSourceBasisReferenceV1;pub use prediction::RawSourceBindingV1;pub use prediction::RawSourceCoordinateBasisV1;pub use prediction::RawSourceDispositionV1;pub use prediction::RawSourceDomainV1;pub use prediction::RawSourceFieldIdV1;pub use prediction::RawSourceKeyV1;pub use prediction::RawSourceObservationStateWireV1;pub use prediction::RawSourceObservationWireV1;pub use prediction::RawSourceProjectionWorkWireV1;pub use prediction::RawSourceProvenanceKindV1;pub use prediction::RawSourceProvenanceV1;pub use prediction::RawSourceSetCoverageStateV1;pub use prediction::RawSourceSetCoverageV1;pub use prediction::ResolvedSettingLocationV1;pub use prediction::SourceSkeletonRowKindV1;pub use profile::ResolvedRoles;pub use profile::RigProfile;pub use profile::Role;pub use profile::builtin_profiles;pub use profile::detect_profile;pub use profile::resolve_configured_roles;pub use sample::PoseGrid;pub use sample::TrackSample;pub use sample::default_frame_count;pub use sample::sample_clip;pub use sample::sample_track;pub use scale::ProofResidualKind;pub use scale::ScaleBoneRestField;pub use scale::ScaleCandidate;pub use scale::ScaleCapabilityCoverage;pub use scale::ScaleCapabilityFacts;pub use scale::ScaleError;pub use scale::ScaleFieldDisposition;pub use scale::ScaleFieldPlan;pub use scale::ScaleFieldTarget;pub use scale::ScaleOperation;pub use scale::ScalePayloadShapeRow;pub use scale::ScalePlan;pub use scale::ScalePlanLedger;pub use scale::ScaleProjectedRole;pub use scale::ScaleProof;pub use scale::ScaleProofObligation;pub use scale::ScaleProofResidual;pub use scale::ScaleRequest;pub use scale::ScaleRewriteRule;pub use scale::ScaleSourceNodeKind;pub use scale::ScaleSourceRestField;pub use scale::ScaleSourceTopologyRow;pub use scale::ScaleTolerancePolicy;pub use scale::plan_scale;pub use scale::prove_scale;pub use skinned_canonical::SkinnedBindPoseCanonicalization;pub use skinned_canonical::SkinnedBindPoseCanonicalizationError;pub use skinned_canonical::SkinnedBindPoseCanonicalizationOptions;pub use skinned_canonical::SkinnedBindPosePlacement;pub use skinned_canonical::canonicalize_skinned_bind_pose;pub use source_facts::LoadedSource;pub use source_facts::RAW_SOURCE_FACTS_V1_ID;pub use source_facts::RAW_SOURCE_V1_MAX_CLIPS;pub use source_facts::RAW_SOURCE_V1_MAX_OBSERVATIONS;pub use source_facts::RAW_SOURCE_V1_MAX_RESOURCE_REFERENCES;pub use source_facts::RAW_SOURCE_V1_MAX_TEXT_BYTES;pub use source_facts::RAW_SOURCE_V1_MAX_TOTAL_TEXT_BYTES;pub use source_facts::RAW_SOURCE_V1_MAX_TRAVERSAL_DEPTH;pub use source_facts::RawSourceFactsBuilderV1;pub use source_facts::RawSourceFactsV1;pub use source_facts::SourceAxisV1;pub use source_facts::SourceChannelFactV1;pub use source_facts::SourceChannelPropertyV1;pub use source_facts::SourceClipFactV1;pub use source_facts::SourceComponentMaskV1;pub use source_facts::SourceConstructFactV1;pub use source_facts::SourceConstructKindV1;pub use source_facts::SourceCoordinateBasisV1;pub use source_facts::SourceFactDomainV1;pub use source_facts::SourceFactSetV1;pub use source_facts::SourceFactsError;pub use source_facts::SourceFactsViewV1;pub use source_facts::SourceFormatV1;pub use source_facts::SourceFramesPerSecondV1;pub use source_facts::SourceHandednessV1;pub use source_facts::SourceInterpolationV1;pub use source_facts::SourceLinearUnitV1;pub use source_facts::SourceLoaderDispositionV1;pub use source_facts::SourceLogicalLocatorV1;pub use source_facts::SourceObservationStateV1;pub use source_facts::SourceObservationV1;pub use source_facts::SourceProjectionWorkV1;pub use source_facts::SourceProvenanceKindV1;pub use source_facts::SourceProvenanceV1;pub use source_facts::SourceRelativeLocatorV1;pub use source_facts::SourceResourceKindV1;pub use source_facts::SourceResourceLocatorV1;pub use source_facts::SourceResourceReferenceV1;pub use source_facts::SourceSetCoverageStateV1;pub use source_facts::SourceSetCoverageV1;pub use source_facts::SourceTargetKindV1;pub use source_facts::SourceTargetV1;pub use source_facts::SourceTextV1;pub use source_facts::SourceTimeRangeV1;pub use static_bake::StaticMeshBake;pub use static_bake::StaticMeshBakeError;pub use static_bake::StaticMeshBakeEvidence;pub use static_bake::StaticMeshBakeInstanceEvidence;pub use static_bake::bake_static_mesh_transforms;pub use glam;
Modules§
- assembly
- Lossless, name-based clip operations for character-assembly pipelines.
- check
- The check abstraction, its execution context, and the built-in check sets.
- config
- Typed configuration: rig selection, per-check settings, per-clip
expectations and movement ownership, and typed clip groups. The TOML file (
animsmith.toml) is one constructor of this — embedding pipelines build it programmatically through this module and keep their own contract formats on their side. - contract
- Versioned JSON result-contract types shared by CLI and embedded producers.
- dependency_
closure - Bounded identities for a source file and its declared resource closure.
- diff
- Compare measurement maps and report per-metric movement beyond significance thresholds.
- engine_
contract - Registry-independent engine profile facts and resolved settings.
- evaluation
- Typed check-evaluation records.
- finding
- Structured lint findings. The structured fields (not just a message
string) are what make
diff, the JSON schema, and the HTML report cheap downstream. - measure
- Measurements: the raw per-clip metric map that
measureemits andlintjudges. Kept separate from findings so pipelines (e.g. a bake’s measured sidecar) can pin their own contracts to the numbers. - metrics
- Locomotion clip metrics: loop-seam ratio, gait phase, root-motion speed, and sampled root trajectory. The loop-seam, gait, and speed metrics were ported from a production game pipeline’s reference implementation (verified there against Blender pose-matrix FK to <0.01×) — the algorithms are kept semantically identical so the numbers reproduce.
- model
- The loader-facing layer: clips, tracks, and the skeleton before metric
resampling or repair. The glTF loader preserves authored animation
values; the FBX loader normalizes scene coordinates and bakes takes to
linear TRS tracks. Mechanical checks (NaN, quaternion flips, key
density, …) read this layer; semantic checks read the sampled layer
built from it (see
crate::sample). - prediction
- Registry-independent engine-prediction provenance and per-check evidence.
- profile
- Rig profiles: checks never reference bone names, they reference roles. A profile maps roles to name matchers; built-ins cover the common rigs and auto-detection scores every built-in by resolved-role coverage. A check whose required roles do not resolve reports a typed coverage gap — never a false failure.
- sample
- The sampled layer: what a game runtime sees. A
PoseGridis a uniform time grid over[0, duration]sampled with glTF-spec interpolation semantics (lerp for T/S, shortest-path slerp for R, STEP hold, cubic-spline Hermite; clamp at the ends), then FK’d to model space. - scale
- Format-neutral scale plan and proof contracts (DESIGN.md Appendix D).
- skinned_
canonical - Bind-pose canonicalization for skinned character geometry.
- source_
facts - Bounded, format-neutral observations retained from a source loader.
- static_
bake - Canonical baking of static mesh node transforms into vertex data.
- transform
- Pipeline-mechanical clip transforms, ported from the incubating bake’s Python: frame-window slicing, hold-extension, duplicate-endpoint removal, and gait-anchor rotation. Scope rule (DESIGN.md §1): animsmith may rewrite a clip only in ways whose correctness its own checks can verify.