Animation files#
A .anim file is a clip, written as JSON. Most clips are made in the
animation editor or imported from Blockbench, and you only
read this page to write one by hand or to know what a field does. To play a clip, see
Animations.
There are two layouts:
- Curves per joint, versions 2 and 3. Each joint has its own curves for rotation, position and scale. The Blockbench importer and the animation editor write this layout.
- Poses at keyframes, version 1, the older layout. It lists whole poses at keyframes.
Version 3 is version 2 with more in it: key types, easings, handle types, curve modifiers, track settings, ping-pong loops, autoplay, a speed, and sound and clip tracks. Every version 2 file is a valid version 3 file and reads the same.
A clip of curves#
{
"version": 2,
"length": 1,
"loop": "loop",
"priority": "movement",
"euler": "yxz",
"joints": {
"rightLeg": {
"rotation": [
[0, [30, 0, 0], "catmullrom"],
[0.5, [-30, 0, 0], "catmullrom"],
[1, [30, 0, 0]]
]
},
"torso": {
"position": [
[0, [0, 0, 0], "bezier", { "out": [0.1, [0, 0.05, 0]] }],
[0.25, [0, 0.06, 0], "bezier", { "in": [-0.1, 0], "out": [0.1, 0] }],
[0.5, [0, 0, 0], "step"]
],
"weight": 0.8
}
},
"mask": ["rightLeg", "leftLeg", "torso"],
"blend": "normal",
"markers": [{ "time": 0.25, "name": "step", "value": "right" }],
"events": [{ "time": 0.75, "name": "sound", "payload": { "effect": "step", "volume": 0.6 } }]
}This swings the right leg back and forth once a second and bobs the torso up and down at 0.8 of its
weight. Only joints is required.
Clip fields#
Playback:
| Field | |
|---|---|
version |
3, or 2 for files from before. A file with joints is read as curves per joint either way |
length |
seconds; the last key or marker when left out |
loop |
loop starts over, once stops at the end, hold stays on the last frame until stopped, pingpong runs back from the end and forth again. once when left out |
speed |
how fast the clip plays, times the track's own speed. 1 when left out |
autoplay |
true starts the clip on its model or body when the place starts, see autoplay |
priority |
core, idle, movement, action, action2, action3, action4, or a number. core when left out. See priority and weight |
mask |
a list of joint names, or one string of names split by commas or spaces. Only those joints are moved |
blend |
normal, or additive |
space |
body, or view for a clip that plays on the view model. A body's animator refuses a view clip |
Joints:
| Field | |
|---|---|
joints |
joint name to its channels, see joints. Required |
euler |
the order the three rotation angles are put together in, like yxz (the default, the same as cframe.angles) or zyx (Blockbench's) |
skeleton |
the hierarchy the clip was made on, see playing an imported clip on a body |
retarget |
joint name in the clip to the body joint it plays on, overriding the guess from its name. An empty name keeps that joint off a body |
Things that happen at a time:
| Field | |
|---|---|
markers |
each with a time, a name and an optional string value. See markers and events |
events |
each with a time, a name, a payload, which is any JSON, and an on: server, client or both, where it fires. both when left out |
sounds |
each with a time, a sound id and an optional volume and pitch. The clients play it where the rig stands when the playhead passes it |
plays |
each with a time, a clip, the res:// path of another .anim, and a fade in seconds. When the server's playhead passes it, the clip starts on the same animator, or starts again if it already plays |
For the editor only:
| Field | |
|---|---|
rig |
the rig the clip was made for: player, view, the res:// path of the .bbmodel a model was made from, or a model's name |
fps, viewModel |
written by the editor for itself, as is an event's preview. The engine reads past them |
Joints#
A joint has up to three channels, a weight, and the settings of its track:
| Field | Values |
|---|---|
rotation |
[x, y, z] angles in degrees, put together in the file's euler order, or [x, y, z, w], a quaternion |
position |
[x, y, z], the offset from the joint's rest, in blocks |
scale |
[x, y, z], 1 is the joint's own size. On a body joint it is the joint's scale |
weight |
0 to 1, how much of the joint the clip takes; 1 when left out |
muted |
true and the track does not play. Its keys stay in the file |
locked |
true and the editor will not change its keys. The engine reads past it |
interpolation |
the interpolation the editor gives new keys on this track, linear, catmullrom, bezier or step. The engine reads past it |
modifiers |
curve modifiers per channel, { "rotation": [ ... ] }, see curve modifiers |
Channels a joint does not have are left alone. A clip with only rotations turns the joints and does not pull their positions back to the rest.
Keys#
A channel is a list of keys, and a key is [time, value, interpolation, extra]. The last two are
optional.
"rightArm": {
"rotation": [
[0, [24, 0, 0], "bezier", { "type": "extreme", "left": "autoClamped", "right": "autoClamped", "out": [0.1, [-4, 0, 0]] }],
[0.3, [0, 0, 0], "back", { "type": "breakdown", "ease": "out" }],
[0.6, [-24, 0, 0]]
],
"interpolation": "bezier",
"modifiers": { "rotation": [{ "type": "cycles", "before": "repeat", "after": "offset" }] }
}Interpolation#
The interpolation says how the value travels from this key to the next one:
| Interpolation | |
|---|---|
linear |
a straight line. The default |
catmullrom |
a smooth curve through every key, bent by the keys on either side |
bezier |
a curve shaped by this key's out handle and the next key's in handle |
step |
holds this key's value, then jumps to the next key when its time comes |
sine, quad, cubic, quart, quint, expo, circ, back, bounce, elastic |
an easing from this key to the next, the same curves as tweens. ease in the extra picks in, out or inOut; left out, back, bounce and elastic ease out and the rest ease in |
Angles are interpolated one axis at a time, as Blockbench does, so a key can spin a joint more than
half a turn. Quaternion keys slerp, and treat catmullrom and bezier as linear.
Two keys at the same time make a jump: the value arrives at the first and leaves from the second.
The extra#
The extra is an object, and every field of it is optional:
| Field | |
|---|---|
in, out |
the bezier handles, see bezier handles |
ease |
in, out or inOut for an easing key |
type |
keyframe (left out), breakdown, extreme, jitter or hold. They only mark what a key is for; the engine plays them all the same |
left, right |
the type of the in and out handle: autoClamped, auto, vector, aligned or free (left out) |
The editor works out autoClamped, auto and vector handles from the keys around them and writes
the result in in and out. The engine only ever reads the handles.
Bezier handles#
Handles are { "in": [dt, dv], "out": [dt, dv] }:
dtis the handle's time from its key, in seconds, negative forin.dvis how far the handle is from the key's value: one number for all three axes, or[dx, dy, dz].
The two handles of a segment share one time line, so the three axes ease in step, and a handle only moves its own axis's value. A missing handle is flat and a third of the segment long, which gives an ease in and out.
Curve modifiers#
A curve modifier changes a whole channel without touching its keys. Modifiers run in the order they are listed, the ones that move time first. They work on angle and offset channels, not on quaternion keys.
Each has two optional fields:
axis:0,1or2for x, y or z. Every axis when left out.enabled:truewhen left out.
type |
Fields | |
|---|---|---|
cycles |
before, after: none, repeat (the default), offset or mirror |
repeats the keyed range before the first key and after the last. offset climbs by the change over the range each cycle, mirror runs every second cycle backwards |
noise |
scale (seconds, 1), strength (1), phase (0), offset (0) |
adds a smooth wobble, the same every time it plays, half the strength either way |
stepped |
step (seconds, 0.1), offset (0) |
holds the curve on a grid of times, for a choppy look |
limits |
min, max |
clamps the value; a side left out is not limited |
envelope |
reference (0), min (-1), max (1), points: [time, min, max] |
stretches the curve: reference plus min and plus max land on the min and max of the points around the time |
Version 1: poses at keyframes#
{
"length": 1,
"looped": true,
"priority": 1,
"keyframes": [
{ "time": 0, "poses": { "rightLeg": { "angles": [30, 0, 0], "easing": "sine" },
"leftLeg": { "angles": [-30, 0, 0], "easing": "sine" } } },
{ "time": 0.5, "poses": { "rightLeg": { "angles": [-30, 0, 0], "easing": "sine" },
"leftLeg": { "angles": [30, 0, 0], "easing": "sine" } } },
{ "time": 1, "poses": { "rightLeg": { "angles": [30, 0, 0] },
"leftLeg": { "angles": [-30, 0, 0] } } }
],
"markers": [
{ "time": 0.25, "name": "step", "value": "right" },
{ "time": 0.75, "name": "step", "value": "left" }
]
}| Field | ||
|---|---|---|
length |
optional | seconds; the last keyframe's time when left out |
looped |
optional | false when left out |
priority |
optional | a number or a level name; 0 when left out |
keyframes |
each with a time and poses, a table of joint name to pose |
|
markers |
optional | each with a time, a name and an optional value |
mask, blend, space |
optional | as in version 2 |
A pose:
| Field | |
|---|---|
position |
[x, y, z], the offset from the joint's rest |
rotation |
[x, y, z, w], a quaternion |
angles |
[x, y, z] in degrees, used when there is no rotation |
easing |
same names as tweens; linear when left out |
direction |
in, out or inOut; inOut when left out |
weight |
0 to 1; 1 when left out |
Everything a pose leaves out is the rest: no offset and no turn. Markers have their own times and do not belong to a keyframe, so you can put a marker between two keyframes.
The animation editor opens a version 1 clip as it is, and writes it as version 3 when you save it.
The .retarget file#
A .retarget file maps the joints of a clip onto a rig that names or rests its bones differently.
A track uses it through retargetId, see
Playing a clip on another rig.
{
"version": 1,
"source": "res://models/knight.bbmodel",
"target": "res://models/goblin.bbmodel",
"scale": 0.8,
"joints": {
"Body": "spine",
"LeftArm": { "to": "arm_l", "source": [0, 0, 0], "target": [0, 0, -90] },
"Cape": ""
}
}| Field | ||
|---|---|---|
joints |
clip joint to the rig joint it plays on. An empty name keeps that joint still | |
to |
the rig joint, when the entry is an object | |
source, target |
optional | the joint's rest rotation on the rig the clip was made on and on this rig, in the rig's own space: [x, y, z] degrees in yxz order, or a quaternion. With both, the joint's turns are carried across as the same turn in the world, so a bone that rests pointing sideways still swings the way the clip's bone did |
scale |
optional | positions are multiplied by it, for a rig of another size. 1 when left out |
source, target at the top |
optional | the rigs the map was made for. Only the editor reads them |
A joint the file does not name plays on the rig joint of the same name, if there is one. Masks take either name. The animation editor writes these files, see Retargeting.
