Skip to content

Releases

v0.9.0

Choose a tag to compare

@rawframe-release rawframe-release released this 02 Nov 19:09
9752834

0.9.0 (2026-11-02)

Changed

  • Breaking: maniSkeleton_BlendPoses refuses a threshold below
    FLT_MIN.
    The threshold must be at least FLT_MIN (2^-126) and at
    most 1. A subnormal threshold, which 0.8.0 accepted and which could
    blend translations and scales to infinity or NaN, now returns
    mani_errorInvalid and leaves the output pose as it was. Graphs blend
    at MANI_BLEND_THRESHOLD (1e-5) and are not affected
    (#216).

Fixed

  • Sampling a clip between two rotation samples in opposite hemispheres
    could give the identity rotation. A clip file may hold such samples,
    for example (1, 0, 0, 2^-80) and (-1, 0, 2^-80, 0); halfway between
    them, the interpolated rotation is too short for its squared length to
    be a normal binary32. It is now scaled by a power of two before it is
    normalized, so it keeps its direction. The builder keeps consecutive
    samples in one hemisphere, so built clips do not reach this case
    (#211).
  • The skinning jobs gave a zero normal or tangent for a direction that
    had not collapsed when the palette's scale was far from 1: a uniform
    scale of about 2^-40 or 2^40 for normals, and 2^-70 or 2^70 for
    tangents. They now keep its direction. Only a zero direction, or one
    that is not finite, still comes out zero
    (#214).

Results change only for the inputs above, which gave the identity or a
zero direction before. Every other pose, sample, skinned vertex, file
byte and format version is the same, and no pinned hash moves. As with
every release before 1.0.0, a graph instance, spring state or trainer
checkpoint saved by 0.8.0 is refused with mani_errorVersion: keep
assets, not saved states, across the upgrade.

v0.8.0

Choose a tag to compare

@rawframe-release rawframe-release released this 01 Nov 14:39
3c271ae

0.8.0 (2026-10-31)

Changed

  • Breaking: kinds, modes and choices are int32_t, and flag sets have
    uint32_t typedefs.
    All 33 kind, mode and choice typedefs, such as
    maniLoopPolicy, are int32_t; a negative value is refused like one
    past the last value. New flag-set typedefs are maniGraphSyncFlags,
    maniGraphClipFlags, maniRootAxes and maniMatchEntryFlags, and the
    fields that hold them take them, as does maniClipSource.loop, now a
    maniLoopPolicy. Rename MANI_MATCH_LOOP, MANI_MATCH_NO_JUMP and
    MANI_MATCH_MIRRORED to maniMatchEntryLoop, maniMatchEntryNoJump
    and maniMatchEntryMirrored. maniMorphTargets_GetAttribute returns
    -1 past the count, where it returned UINT32_MAX. Code that keeps a
    kind in a uint32_t variable or compares it with an unsigned value
    updates its types
    (#199).
  • Breaking: two names follow the family's naming rules.
    maniLearnedTrainerReport.iteration is iterationCount, and
    maniRootMoveIdentity is maniMakeRootMoveIdentity
    (#198).
  • Breaking: the CPU checks return bool, and maniHash64 takes an
    int64_t count.
    maniIsCpuBackendSupported and maniCheckCpu
    return bool instead of an int32_t 1 or 0, so a caller comparing
    the result with 1 tests it as a bool. maniHash64 hashes any byte
    count up to INT64_MAX; pass the count without narrowing it. Hash
    values are unchanged
    (#176).
  • Breaking: a refused call or a "no" clears its outputs. A call on a
    builder, a glTF or FBX document or a trainer clears its sizes, counts,
    reports, structs and handles before any check, so a failed call never
    leaves an earlier call's value to be read as its answer.
    maniBuilder_CopyBuilt, maniBuilder_CopySkeletonOrder,
    maniGltf_GetMorphWeights, maniFbx_GetMorphWeights and
    maniLearnedTrainer_SaveCheckpoint also zero the caller's array up to
    its capacity; a short skeleton order is no longer filled as far as it
    goes. A too-small buffer still reports the size or count it needed.
    maniBuildGltfClip and maniBuildFbxClip write boundOut only when
    the clip builds. maniClip_GetRootMotionSource and
    maniInfluences_GetCenter clear their output when they return false,
    and the name getters of learned models and motion databases clear
    lengthOut when they return NULL. The headers say what each output
    holds after a failure
    (#165,
    #174).
  • Breaking: a call refused as busy leaves its outputs. A builder or
    trainer call that its own allocator or task hook made is refused with
    mani_errorBusy and writes none of its outputs, since they may be the
    ones the call in progress is filling. maniOpenGltf and
    maniOpenFbx still set their handle to NULL
    (#173).
  • Breaking: more calls back in from host code are refused as busy.
    maniGltf_SupplyBuffer, maniGltf_ReadSprings and
    maniGltf_ReadRagdoll return mani_errorBusy when called from the
    builder's allocator. maniLearnedTrainer_SaveCheckpoint and
    maniBuildLearnedModelFromTrainer return it when called from the
    trainer's allocator or task hooks. While a model is built from a
    trainer, maniLearnedTrainer_Train,
    maniLearnedTrainer_RestoreCheckpoint and
    maniDestroyLearnedTrainer on that trainer return it too. Each
    refusal counts one misuse
    (#187,
    #197).
  • The headers say which outputs may be their input:
    maniBlendRootMotion's moveOut may be one of moves,
    maniLearnedModel_Project's stateOut may be query, and
    maniMorphTargets_ComputeTargetWeights' targetWeightsOut may be
    channelWeights
    (#195).

Fixed

  • maniMorphTargets_ComputeTargetWeights gave wrong weights when its
    output was its own channel weights. It now computes them in place with
    the same bits as apart
    (#193).
  • maniRetargetMap_RetargetPose gave a wrong pose when the target pose
    was the source pose, or shared memory with it. It now refuses any
    overlap of the two poses with mani_errorInvalid and writes nothing
    (#194).
  • Destroying a builder or a trainer, or closing a glTF or FBX document,
    let the host's free hook call back into the object: a hook could
    build on a builder being destroyed, free it twice, or read a closing
    document's freed names. Every call from those frees is now refused
    with mani_errorBusy, and a closing document reads as empty
    (#187).
  • Host code running while a model was built from a trainer could
    destroy or retrain the trainer under the build, which then read freed
    memory. The trainer is now marked busy for the whole build
    (#197).

Poses, samples, file bytes and format versions do not change. As with
every release before 1.0.0, a graph instance, spring state or trainer
checkpoint saved by 0.7.0 is refused with mani_errorVersion: keep
assets, not saved states, across the upgrade.

v0.7.0

Choose a tag to compare

@rawframe-release rawframe-release released this 29 Oct 14:46
e2e1d4b

0.7.0 (2026-10-29)

Changed

  • Breaking: every call is named by the Maul family's naming rule. A
    call on one object is named maniObject_Verb: a getter
    maniObject_GetThing, a predicate maniObject_IsThing. The object is
    the library object the call takes first, such as a clip, a pose, a
    skeleton, a graph instance, a builder or a glTF document, even where
    the call only reads it: maniSampleClip is maniClip_Sample,
    maniClipDuration is maniClip_GetDuration, maniPoseIsDifference
    is maniPose_IsDifference and maniBlendPoses is
    maniSkeleton_BlendPoses. Creation, destruction and calls with no
    object keep a verb first: every maniOpen..., maniInit...,
    maniCreate... and maniBuild... keeps its name, and the importers'
    builds take that shape (maniGltfBuildClip is maniBuildGltfClip).
    The misuse counts are maniBuilder_GetMisuse and
    maniLearnedTrainer_GetMisuse, maniResultName is
    maniGetResultName, the CPU check is maniIsCpuBackendSupported, and
    the task hook types end in Function. Math on plain values keeps its
    name (maniRootMoveIdentity, maniComposeRootMotion,
    maniDecomposeAffine, maniHash64). Rename every call in the table
    below; the parameters stay the same, except for maniPose_AddLayers
    (#156).
  • Breaking: maniPose_AddLayers takes the pose first. A pose a call
    changes in place is its object, so maniAddPoses(skeleton, pose, layers, count) is maniPose_AddLayers(pose, skeleton, layers, count). Swap the first two arguments; a compiler refuses or warns
    about the old order, since the two pointers have different types. The
    IK solvers already took the pose first and keep their order as
    maniPose_SolveTwoBone and the others
    (#156).
  • The user guides and the API reference use the new names
    (#156).

Poses, samples and file bytes do not change; only the names do. As
with every release before 1.0.0, a graph instance, spring state or
trainer checkpoint saved by 0.6.0 is refused with mani_errorVersion:
keep assets, not saved states, across the upgrade.

Before After
maniResultName maniGetResultName
maniTaskFn maniTaskFunction
maniEnqueueTaskFn maniEnqueueTaskFunction
maniFinishTaskFn maniFinishTaskFunction
maniPoseDifference maniSkeleton_ComputePoseDifference
maniBlendPoses maniSkeleton_BlendPoses
maniBuildMask maniSkeleton_BuildMask
maniAddPoses maniPose_AddLayers
maniBodyIkScratchSize maniSkeleton_GetBodyIkScratchSize
maniSolveBodyXpbd maniPose_SolveBodyXpbd
maniSolveBodySdls maniPose_SolveBodySdls
maniBuilderMisuses maniBuilder_GetMisuse
maniMeasureClip maniBuilder_MeasureClip
maniCopyBuilt maniBuilder_CopyBuilt
maniCopySkeletonOrder maniBuilder_CopySkeletonOrder
maniClipCompressed maniClip_IsCompressed
maniClipDuration maniClip_GetDuration
maniClipSampleRate maniClip_GetSampleRate
maniClipSampleCount maniClip_GetSampleCount
maniClipLoopPolicy maniClip_GetLoopPolicy
maniClipAdditiveBasis maniClip_GetAdditiveBasis
maniClipIdentity maniClip_GetIdentity
maniClipSkeletonIdentity maniClip_GetSkeletonIdentity
maniSampleClip maniClip_Sample
maniClipFloatTrackCount maniClip_GetFloatTrackCount
maniClipFloatTrackName maniClip_GetFloatTrackName
maniSampleClipBones maniClip_SampleBones
maniClipCursorSize maniClip_GetCursorSize
maniClipCursorCompactSize maniClip_GetCursorCompactSize
maniSampleClipCursor maniClipCursor_Sample
maniSampleClipFloatsCursor maniClipCursor_SampleFloats
maniClipFindFloatTrack maniClip_FindFloatTrack
maniSampleClipFloats maniClip_SampleFloats
maniClipDiscreteTrackCount maniClip_GetDiscreteTrackCount
maniClipDiscreteTrackName maniClip_GetDiscreteTrackName
maniClipFindDiscreteTrack maniClip_FindDiscreteTrack
maniClipDiscreteValue maniClip_GetDiscreteValue
maniClipEventCount maniClip_GetEventCount
maniClipEventAt maniClip_GetEvent
maniClipEventRange maniClip_GetEventRange
maniClipMarkerCount maniClip_GetMarkerCount
maniClipMarkerAt maniClip_GetMarker
maniGraphIdentity maniGraph_GetIdentity
maniGraphSkeletonIdentity maniGraph_GetSkeletonIdentity
maniGraphNodeCount maniGraph_GetNodeCount
maniGraphParameterCount maniGraph_GetParameterCount
maniGraphFindParameter maniGraph_FindParameter
maniGraphParameterTypeOf maniGraph_GetParameterType
maniGraphParameterName maniGraph_GetParameterName
maniGraphClipCount maniGraph_GetClipCount
maniGraphClipIdentity maniGraph_GetClipIdentity
maniGraphClipName maniGraph_GetClipName
maniGraphDatabaseCount maniGraph_GetDatabaseCount
maniGraphDatabaseIdentity maniGraph_GetDatabaseIdentity
maniGraphDatabaseName maniGraph_GetDatabaseName
maniGraphModelCount maniGraph_GetModelCount
maniGraphModelIdentity maniGraph_GetModelIdentity
maniGraphModelName maniGraph_GetModelName
maniGraphSpringSetCount maniGraph_GetSpringSetCount
maniGraphSpringSetIdentity maniGraph_GetSpringSetIdentity
maniGraphSpringSetName maniGraph_GetSpringSetName
maniGraphRetargetMapCount maniGraph_GetRetargetMapCount
maniGraphRetargetMapIdentity maniGraph_GetRetargetMapIdentity
maniGraphMirrorMapIdentity maniGraph_GetMirrorMapIdentity
maniGraphRetargetMapSourceIdentity maniGraph_GetRetargetMapSourceIdentity
maniGraphClipRetargetMap maniGraph_GetClipRetargetMap
maniGraphNodeKindOf maniGraph_GetNodeKind
maniGraphNodeInputCount maniGraph_GetNodeInputCount
maniGraphNodeInput maniGraph_GetNodeInput
maniGraphOutputNode maniGraph_GetOutputNode
maniGraphNodeSourcePlace maniGraph_GetNodeSourcePlace
maniGraphBindingSize maniGraph_GetBindingSize
maniGraphInstanceSize maniGraphBinding_GetInstanceSize
maniSetGraphParameter maniGraphInstance_SetParameter
maniSetGraphPose maniGraphInstance_SetPose
maniGetGraphPose maniGraphInstance_GetPose
maniGetGraphParameter maniGraphInstance_GetParameter
maniInspectGraphNode maniGraphInstance_InspectNode
maniSaveGraphInstance maniGraphInstance_Save
maniRestoreGraphInstance maniGraphInstance_Restore
maniUpdateGraph maniGraphInstance_Update
maniGraphScratchSize maniGraphBinding_GetScratchSize
maniEvaluateGraph maniGraphInstance_Evaluate
maniGraphSubsetSize maniGraphBinding_GetSubsetSize
maniGraphSubsetBones maniGraphSubset_GetBones
maniEvaluateGraphSubset maniGraphInstance_EvaluateSubset
maniSolveTwoBone maniPose_SolveTwoBone
maniSolveAim maniPose_SolveAim
maniSolveCcd maniPose_SolveCcd
maniSolveFabrik maniPose_SolveFabrik
maniGltfBufferCount maniGltf_GetBufferCount
maniGltfBufferUri maniGltf_GetBufferUri
maniGltfSupplyBuffer maniGltf_SupplyBuffer
maniGltfSkeletonCount maniGltf_GetSkeletonCount
maniGltfSkinCount maniGltf_GetSkinCount
maniGltfSkinSkeleton maniGltf_GetSkinSkeleton
maniGltfNodeCount maniGltf_GetNodeCount
maniGltfBuildSkeleton maniBuildGltfSkeleton
maniGltfBuildNodeSkeleton maniBuildGltfNodeSkeleton
maniGltfSkeletonPlacement maniGltf_GetSkeletonPlacement
maniGltfBuildSkin maniBuildGltfSkin
maniGltfNodeBoneName maniGltf_GetNodeBoneName
maniGltfRenamedCount maniGltf_GetRenamedCount
maniGltfRenamedNode maniGltf_GetRenamedNode
maniGltfAnimationCount maniGltf_GetAnimationCount
maniGltfAnimationName maniGltf_GetAnimationName
maniGltfBuildClip maniBuildGltfClip
maniGltfReadSprings maniGltf_ReadSprings
maniGltfReadRagdoll maniGltf_ReadRagdoll
maniGltfMeshCount maniGltf_GetMeshCount
maniGltfPrimitiveCount maniGltf_GetPrimitiveCount
maniGltfPrimitiveTargetCount maniGltf_GetPrimitiveTargetCount
maniGltfNodeMesh maniGltf_GetNodeMesh
maniGltfNodeSkin maniGltf_GetNodeSkin
maniGltfMorphWeights maniGltf_GetMorphWeights
maniGltfBuildInfluences maniBuildGltfInfluences
maniGltfBuildMorphTargets maniBuildGltfMorphTargets
maniFbxVersion maniFbx_GetVersion
maniFbxModelCount maniFbx_GetModelCount
maniFbxModelBoneName maniFbx_GetModelBoneName
maniFbxRenamedCount maniFbx_GetRenamedCount
maniFbxRenamedModel maniFbx_GetRenamedModel
maniFbxSkeletonCount maniFbx_GetSkeletonCount
maniFbxSkinCount maniFbx_GetSkinCount
maniFbxSkinSkeleton maniFbx_GetSkinSkeleton
maniFbxSkinModel maniFbx_GetSkinModel
maniFbxReadSettings maniFbx_ReadSettings
maniFbxBuildSkeleton maniBuildFbxSkeleton
maniFbxBuildModelSkeleton maniBuildFbxModelSkeleton
maniFbxSkeletonPlacement maniFbx_GetSkeletonPlacement
maniFbxBuildSkin maniBuildFbxSkin
maniFbxSkinMethod maniFbx_GetSkinMethod
maniFbxBuildInfluences maniBuildFbxInfluences
maniFbxMorphCount maniFbx_GetMorphCount
maniFbxMorphModel maniFbx_GetMorphModel
maniFbxMorphTargetCount maniFbx_GetMorphTargetCount
maniFbxBuildMorphTargets maniBuildFbxMorphTargets
`maniFbxMorphWeig...
Read more

v0.6.0

Choose a tag to compare

@rawframe-release rawframe-release released this 29 Oct 02:20
ff294cd

0.6.0 (2026-10-29)

Changed

  • Breaking: a saved state is read only by the release that wrote
    it.
    A saved graph instance and a saved spring state start with the
    Maul family's 16-byte state prefix (magic, MANI_ABI_VERSION, format
    version, header size), so their headers are 32 bytes and every saved
    state's bytes change. maniRestoreGraphInstance,
    maniRestoreSpringState and maniRestoreLearnedCheckpoint refuse a
    state written by a release of another ABI version with
    mani_errorVersion: before 1.0.0 that is any other release, from
    1.0.0 another minor release. A state saved by 0.5.0 or earlier is
    refused. Keep assets, not saved states, across an upgrade. Poses,
    samples and file bytes do not change
    (#134).
  • Breaking: each save call reports the saved size.
    maniSaveGraphInstance, maniSaveSpringState and
    maniSaveLearnedCheckpoint take a sizeOut after the capacity, and a
    NULL buffer with capacity 0 measures. maniGraphStateSize,
    maniSpringSavedSize and maniLearnedCheckpointSize are removed:
    call the save with a NULL buffer instead
    (#129).
  • Breaking: every call that fills an array takes its capacity and
    reports the count.
    maniMotionDatabaseFeatures,
    maniMotionDatabaseNormalization, maniLearnedModelNormalization,
    maniMorphTargetWeights and maniLearnedProject take a capacity and
    a countOut after the array; maniGltfMorphWeights and
    maniFbxMorphWeights take a capacity in place of the exact count, and
    a countOut; maniRagdollBodiesFromPose, maniRagdollJointTargets
    and maniBuildMask take a countOut after the capacity.
    maniLearnedOutput gains floatTrackCapacity and eventCapacity
    after its arrays. A NULL array with capacity 0 measures
    (#133).
  • Breaking: name lengths are size_t. Every name getter (the
    skeleton's bones, a clip's tracks, the graph's slots and parameters, a
    motion database's channels, a learned model's tracks and events, morph
    channels and targets, a spring set's springs, and the glTF and FBX
    importers' names) reports a length through size_t*, and every name
    length a public struct carries is size_t, so a name read from one
    call passes into a source unchanged. A builder refuses a name longer
    than the new MANI_MAX_NAME_BYTES (2^31 - 1 bytes) with
    mani_errorLimit, at the reason and item it gives that name
    otherwise; before, a morph channel name past it was refused with
    mani_errorInvalid, and a graph event name past it was hashed as if
    empty
    (#135,
    #138).
  • Breaking: the graph's retargeting maps are named as such.
    maniGraphMapCount, maniGraphMapIdentity,
    maniGraphMapSourceIdentity and maniGraphClipMap are
    maniGraphRetargetMapCount, maniGraphRetargetMapIdentity,
    maniGraphRetargetMapSourceIdentity and maniGraphClipRetargetMap;
    MANI_MAX_GRAPH_MAPS is MANI_MAX_GRAPH_RETARGET_MAPS;
    maniGraphClipSource.map is retargetMap, and maniGraphAssets.maps
    and mapCount are retargetMaps and retargetMapCount
    (#136).
  • Every builder's reference names the MANI_MAX_NAME_BYTES refusal, and
    the getting-started guide gives the bound as an example of a fixed one
    (#155).

Fixed

  • The motion database builder no longer writes past its names.
    Channels may name one track, and their names' total was kept in 32
    bits: two channels naming one track of 2^31 + 1 bytes wrapped it, and
    copying the names wrote past the block it sized. Names past 4 GiB in
    all are refused with mani_errorInvalid and maniBuildReasonCount,
    before any name is read, and where size_t has 32 bits, sections past
    what one allocation holds are refused with mani_errorCapacity
    (#143).
  • The mirror map builder sizes its working memory in 64 bits. Where
    size_t has 32 bits (WebAssembly), listed names totalling 4 GiB wrapped
    the room for their partners, which were then written past it; such a
    source is refused with mani_errorCapacity
    (#142).
  • The graph and mirror map builders refuse names past their files'
    32-bit offsets.
    Names or partners past 4 GiB in all were laid out
    with wrapped offsets, so the file built pointed at other bytes; they
    are refused with mani_errorInvalid and maniBuildReasonCount, and
    the mirror map's sections past size_t with mani_errorCapacity
    (#144,
    #151).
  • An imported name past 4 GiB is refused, not cut short. The glTF
    and FBX importers cut a name's decoded length to 32 bits, handing the
    builder the first bytes of the real name; the whole name now reaches
    the builder, which refuses it with mani_errorLimit
    (#153).

v0.5.0

Choose a tag to compare

@rawframe-release rawframe-release released this 28 Oct 20:45
93b811f

0.5.0 (2026-10-28)

Changed

  • Breaking: every file kind's layout and format version change, and
    an opener reads only its own version.
    The reserved words are gone
    from the files: the container header is 48 bytes, not 64, and the
    clip, retargeting map, influences, learned model, learned checkpoint,
    spring set, ragdoll profile and mirror map lose their zero words.
    Every kind's format version goes up by one: skeleton 2, clip 4, graph
    7, retargeting map 3, skin 2, influences 2, morph targets 2, motion
    database 4, learned model 2, learned checkpoint 2, spring set 3,
    ragdoll profile 2, mirror map 3. An opener now refuses any format
    version but its own with mani_errorVersion, an earlier one included;
    it used to accept an earlier version and read it with the current
    layout. Build every stored file again from its source. Poses, samples
    and other outputs do not change; only hashes of file bytes move
    (#113).
  • Breaking: results take the Maul family's values.
    mani_errorVersion is -7 (was -4) and mani_errorFormat is -8 (was
    -3). mani_errorState is removed: a call from an object's own host
    code (its allocator or task hooks) is refused with the new
    mani_errorBusy (-10) in its place, and still counts one misuse. Code
    that compares results by name only renames mani_errorState to
    mani_errorBusy
    (#115).
  • Breaking: a fixed bound passed returns mani_errorLimit (-9). An
    argument, or a builder's or the trainer's source, past a bound the
    library publishes returns mani_errorLimit in place of
    mani_errorInvalid, with the same reason and item. This covers the
    aim, CCD, FABRIK and full-body IK solvers, the motion database search,
    and the skeleton, skin, influences, clip, morph targets, spring set,
    retargeting map, motion database, learned model, trainer and graph
    builders. A bound checked while opening a file is still
    mani_errorFormat, and a range of a parameter's meaning (a weight in
    [0, 1], a cone up to pi) is still mani_errorInvalid. Full-body IK
    scratch that is too small returns mani_errorCapacity, not
    mani_errorInvalid
    (#117).
  • Breaking: the bound constants are named MANI_MAX_*.
    MANI_AIM_MAX_BONES is MANI_MAX_AIM_BONES, MANI_IK_CHAIN_MAX_BONES
    is MANI_MAX_IK_CHAIN_BONES, MANI_IK_MAX_ITERATIONS is
    MANI_MAX_IK_ITERATIONS, MANI_SPRING_MAX_RATE is
    MANI_MAX_SPRING_RATE, MANI_MORPH_MAX_ATTRIBUTES is
    MANI_MAX_MORPH_ATTRIBUTES, and the MANI_BODY_IK_MAX_*,
    MANI_MATCH_MAX_*, MANI_LEARNED_MAX_* and MANI_GRAPH_MAX_* names
    are MANI_MAX_BODY_IK_*, MANI_MAX_MATCH_*, MANI_MAX_LEARNED_* and
    MANI_MAX_GRAPH_*. A name that keeps the old form (MANI_AIM_MAX_CONE,
    MANI_SPRING_MAX_STEPS, MANI_GRAPH_LEARNED_MAX_STEPS) is a range or
    an internal cap, not a bound refused with mani_errorLimit
    (#117).
  • Breaking: public structs have no reserved field. The field is
    removed from every public struct, and builders no longer refuse a
    source for a nonzero one. Remove it from initializers.
    maniFileResult is {result, tag, offset}: tag names the section
    the first wrong byte lies in, 0 in the header and table, so positional
    initializers take the tag second
    (#109).
  • Breaking: a root graph's slots are checked against the root's own
    lists.
    maniBuildGraph refuses, with maniBuildReasonNode at the
    node's place, a root node that names a clip, sync group, database,
    model or spring set slot past the root's own list. In a graph with a
    subgraph such a node used to build with the subgraph's slot of that
    number: with 1 clip in the root and 1 in the subgraph, a root clip
    node naming slot 1 played the subgraph's clip. Only a host's own
    maniGraphSource structs reach this; the JSON form resolves each name
    within its own graph. Every other graph builds to the same bytes. To
    migrate, list in the root every asset and sync group its nodes name
    (#93).
  • MANI_MAX_INFLUENCES (64 weighted influences on a vertex) and
    MANI_MAX_GRAPH_DEPTH (16 levels of subgraphs) are public
    (#117).
  • On WebAssembly, the public calls no longer go through the
    floating-point environment's out-of-line entries, which have nothing
    to switch there, so the static library is about 14.7 KB smaller.
    Results do not change
    (#101).
  • The user guide's getting started page explains mani_errorLimit,
    mani_errorBusy and the one format version a release reads, and its
    examples drop the reserved field and use the new constant names.

Fixed

  • The FBX importer bounds a file's property count. A file with 2^32 - 1
    properties or more wrapped the count, and the importer wrote past the
    property array it had allocated from it. Such a file is now refused
    at the property past the bound; every file under it reads as before
    (#105).
  • A motion database file whose entry is too long for a frame count and
    stores 0xFFFFFFFF as its count is refused at that entry's count. It
    was still refused, but at a later, wrong place. Valid databases open
    and build as before
    (#107).

v0.4.0

Choose a tag to compare

@rawframe-release rawframe-release released this 25 Oct 19:11
844eeba

0.4.0 (2026-10-25)

Changed

  • Breaking: a subgraph's lists and slots are checked like the
    root's.
    maniBuildGraph refuses with maniBuildReasonNode, at the
    node's place, a node inside a subgraph that names a clip, sync group,
    database, model or spring set slot past the subgraph's own list. Such
    a graph used to build when the root had a slot of that number, which
    the node then named: with 2 clips in the subgraph and 9 in the root,
    a clip node naming slot 3 played the root's clip 3. It also refuses
    with maniBuildReasonCount a subgraph with a list whose count is not
    zero and whose pointer is NULL; its clip, sync group, database, model
    and spring set lists used to be read through that pointer when a node
    named one of their slots. Only a host's own maniGraphSource structs
    reach either case; the JSON form resolves and checks its lists. Every
    other graph builds to the same bytes. To migrate, list in each
    subgraph every asset and sync group its nodes name
    (#77).
  • On 32-bit x86 the library is built with SSE2 math
    (-msse2 -mfpmath=sse), so it needs a processor with SSE2, and every
    build now leaves trapping math at the compiler's default, from the
    family's compiler flags. 64-bit builds' tests and pinned hashes pass
    unchanged
    (#73).

Fixed

  • maniBuildGraph refuses a subgraph's sync group whose name is NULL
    with maniBuildReasonCount at item 0, before anything is laid out, as
    it refuses a subgraph's list that is not given. A root's own nameless
    group is still refused by the check with the sync group list's Name
    reason. Only a host's own maniGraphSource structs reach this; the
    JSON form always gives a name. Every graph that built before builds to
    the same bytes
    (#81).

v0.3.0

Choose a tag to compare

@rawframe-release rawframe-release released this 25 Oct 11:02
368e3e8

0.3.0 (2026-10-25)

Changed

  • Breaking: a graph's time scales are bounded. On any path from the
    output, the product of the time scales' sizes must be at most
    MANI_GRAPH_MAX_TIME_FACTOR (1e6), which is far past any playback
    rate a graph needs. A scale that reads a parameter counts at the
    larger size of the parameter's bounds, and a time scale may read only
    a parameter with bounds. Scales on parallel branches never multiply.
    maniBuildGraph refuses a source past either rule with
    maniBuildReasonScalar, and maniOpenGraph refuses such a file with
    mani_errorFormat. Each node record now holds its time factor, so
    the graph format goes from 5 to 6, and maniOpenGraph refuses an
    earlier format with mani_errorVersion. To migrate, give bounds to
    each parameter a time scale reads, and build every graph file again.
    Results do not change for any graph still taken.
    (#66)

Fixed

  • A clip node's step that is not finite moves nothing, and the marker
    walk's count is bounded by two loops of markers. Results do not
    change for steps shorter than about 2^53 clip lengths.
    (#64)
  • A graph's binary32 timers saturate at FLT_MAX: the fade time of a
    machine and of a one-shot, and an inertialize node's step and elapsed
    time. Every timer value below FLT_MAX gives the same bits as
    before.
    (#67)

v0.2.1

Choose a tag to compare

@rawframe-release rawframe-release released this 24 Oct 17:04
d3601a7

0.2.1 (2026-10-24)

Changed

  • The runtime's core (sampling, blending, the model pass, skeletons and
    root motion) is about 1.0 KB smaller at -O2 with GCC: 68,562 bytes,
    against ozz-animation's 69,698. The skeleton's opener and the file
    checks are compiled for size under GCC and Clang. With GCC, opening a
    skeleton takes about 7% more instructions and opening a compressed
    clip about 9% more. Opening a full clip or a motion database does not
    change, and neither does any call made every frame. Results do not
    change.
    (#29)

Fixed

  • The host's allocator and task hooks run in the host's own
    floating-point setting, like the rest of the host's code. In 0.2.0
    they ran in the library's setting while a public call was in
    progress.
    (#27)

v0.2.0

Choose a tag to compare

@rawframe-release rawframe-release released this 24 Oct 14:26
f04b8d1

0.2.0 (2026-10-24)

Changed

  • Breaking: motion matching searches a motion database through an
    exact k-d tree, in place of bounds over runs of frames. Every search
    returns the same frame and cost as before. On large databases a search
    takes far fewer instructions: about 6 times fewer at 100,000 frames
    and up to 16 times fewer at 300,000 frames with the default leaf. On
    small databases with many features (around 5,000 frames and 45
    features) it can be slightly slower. The index takes about 49 bytes a
    frame at the default leaf, up from about 17.
    The motion database format version is 3, and
    maniOpenMotionDatabase refuses any other format version with
    mani_errorVersion. Build databases again from their sources, along
    with the graphs that name them, since a database's identity changes.
    A learned trainer's checkpoint does not resume against a rebuilt
    database.
    maniMotionDatabaseSource gains leafFrames (8, 16 or 32 frames a
    leaf, 0 for 16) and a reserved word that must be 0, so positional
    initializers must name them.
    (#24)

Fixed

  • A host that runs its threads with flush-to-zero, denormals-are-zero
    or another rounding mode now gets the same bits as every other host.
    Every public call that computes switches to the library's
    floating-point setting and restores the host's on return, and so do
    the learned trainer's tasks on the host's worker threads. Results in
    the default setting do not change.
    (#26)

v0.1.0

Choose a tag to compare

@rawframe-release rawframe-release released this 24 Oct 10:34
e5568ce

0.1.0 (2026-10-24)

Changed

  • Compressed clips keep each kind of sub-track together and decode
    several sub-tracks at once: sampling at a random time takes about 28%
    fewer instructions and a forward cursor about 15% fewer, and poses and
    float tracks are the same bits as before.
    The clip format version is 3, and maniOpenClip refuses a clip of
    any other format version, compressed or full precision, with
    mani_errorVersion. Build stored clips again from their sources, or
    compress them again from full-precision clips made with this release.

Fixed

  • A learned motion matching node whose model gives a value past the
    float range, or whose root velocity moves past it over the step, no
    longer passes it on: maniUpdateGraph, maniEvaluateGraph and
    maniEvaluateGraphSubset complete the call with valid, finite
    outputs and return mani_errorFormat, and maniLearnedStep,
    maniLearnedProject and maniLearnedDecompress return
    mani_errorFormat instead of success. maniGraphNodeView's reserved
    word is now failed.