glTF Cubic Spline Keyframe Data Structure

In glTF 2.0 binary files, cubic spline animation data is organized within binary buffers as a contiguous, interleaved array of structural triplets. Rather than storing keyframe values and tangents in separate streams, each keyframe packs an in-tangent, a target value, and an out-tangent in sequence. This article breaks down the exact layout, accessor characteristics, and memory organization used to store cubic spline keyframes inside glTF buffers.

The Keyframe Triplet Layout

When an animation sampler in glTF defines its interpolation algorithm as CUBICSPLINE, the output accessor points to binary data grouped into triplets. For every keyframe index \(k\), the binary stream contains three consecutive elements of identical type:

  1. In-Tangent (inTangent): The incoming tangent vector representing the slope of the curve as it approaches the keyframe.
  2. Point Value (value): The actual animated property value (such as translation, rotation, or scale) at that specific keyframe time.
  3. Out-Tangent (outTangent): The outgoing tangent vector representing the slope of the curve as it leaves the keyframe.

In raw binary representation, for \(n\) keyframes, the buffer contains a sequential array structured conceptually as:

[inTangent_0, value_0, outTangent_0, inTangent_1, value_1, outTangent_1, ..., inTangent_n-1, value_n-1, outTangent_n-1]

Accessor and BufferView Configuration

glTF maps this data using standard bufferView and accessor objects:

  • Element Count: If an animation channel has \(n\) keyframe timestamps in its input accessor, the cubic spline output accessor has a count equal to \(3 \times n\).
  • Type and Component Type: The type (e.g., SCALAR, VEC3, VEC4) and componentType (e.g., 5126 for FLOAT) match the property being animated. For example, a translation track uses VEC3 floats. Therefore, each keyframe occupies three VEC3 elements (9 float values in total: 3 for inTangent, 3 for value, 3 for outTangent).
  • Byte Offset and Stride: The data is packed tightly by default without padding between tangent and value vectors, resulting in a contiguous array where each keyframe payload is \(3 \times \text{sizeOf(type)}\) bytes.

Interpretation During Interpolation

During playback, runtime engines reconstruct cubic Hermite splines between keyframe \(k\) and keyframe \(k+1\). The tangents stored in the buffer are normalized relative to unit time. To evaluate the spline, the runtime scales the out-tangent of keyframe \(k\) and the in-tangent of keyframe \(k+1\) by the duration between the two keyframe timestamps (\(\Delta t = t_{k+1} - t_k\)). Because the tangents and values are stored adjacently in memory, engines can efficiently read all required interpolation parameters with localized cache access.