Transforms and pivots
A target's move, turn, scale and skew become one transform. It turns, scales and skews about a point called its pivot, which can stay in one place or switch from point to point over time.
Pick a pivot
A target turns, scales and skews about its pivot. The clip's pivots gives each target one, in the units of the element its transform is written to. Without one, it is that element's origin: 0, 0.
Pick a pivot below. The tracks stay the same: only pivots changes. The dot marks the pivot, and the turn and the squash leave it where it is. The friend's group sits right in the SVG, so its pivot is in the SVG's own units.
{
"duration": 2.6,
"pivots": {
"friend": { "x": 320, "y": 144 }
},
"tracks": [
{
"targetUid": "friend",
"property": "scaleX",
"keyframes": [
{ "time": 0, "value": 1, "easing": "power2.out" },
{ "time": 0.28, "value": 1.26, "easing": "power2.inOut" },
{ "time": 0.6, "value": 0.86, "easing": "power2.inOut" },
{ "time": 0.92, "value": 1 }
]
},
{
"targetUid": "friend",
"property": "scaleY",
"keyframes": [
{ "time": 0, "value": 1, "easing": "power2.out" },
{ "time": 0.28, "value": 0.74, "easing": "power2.inOut" },
{ "time": 0.6, "value": 1.16, "easing": "power2.inOut" },
{ "time": 0.92, "value": 1 }
]
},
{
"targetUid": "friend",
"property": "rotate",
"keyframes": [
{ "time": 0.7, "value": 0, "easing": "power2.inOut" },
{ "time": 1.9, "value": 360 }
]
}
]
}One matrix per target
Every frame, a target's move, turn, scale and skew go into one matrix: move(x, y) · turn · skew · stretch, the last three about the pivot. Read it from the right: it is stretched, then skewed, then turned, then moved. That order is fixed, whatever the order of the tracks.
Both skews are one skew, as in CSS skew(skewX, skewY), and it turns with the rotation. scale multiplies scaleX and scaleY. A part no track moves rests at its default.
The matrix is written as matrix(a b c d e f) in the element's transform attribute, in place of its own, and destroy() puts its own back. So animate a group around the art, and keep the art's own transforms inside it.
One exception: the outermost <svg> is a box in the page. Its matrix goes in its style, and its pivot is a share of its box (0.5, 0.5 is its middle), written as its transform-origin. An anchor track on it is not kept from jumping: the shift a switch carries is left out there.
xnumberdefault 0- Moves it across, in user units.
ynumberdefault 0- Moves it down, in user units. Up is negative.
rotatenumberdefault 0- Turns it, in degrees. Positive is clockwise.
scalenumberdefault 1- Stretches it both ways: multiplies
scaleXandscaleY. scaleXnumberdefault 1- Stretches it across. 1 is its own size.
scaleYnumberdefault 1- Stretches it up and down.
skewXnumberdefault 0- Slants it along x, in degrees.
skewYnumberdefault 0- Slants it along y, in degrees.
Keyed pivots
An anchor track moves the pivot over time. Each keyframe is two fractions of the target's own box, written "ax ay": "0 0" is its left top, "1 1" its right bottom. The box is the target's entry in the clip's boxes.
A switch is a step: from its keyframe on, the target turns about the new point. The target itself does not jump when it switches. Each switch carries the shift that keeps the matrix exactly what it was at that moment, worked out once when the clip is compiled. So a square that tips over one corner, then the next, rolls along.
The dot is the point it turns about, with the keyframe holding under it. Pick "one pivot" to play the same turn about its first corner the whole way: it swings down through the ground.
{
"duration": 5,
"boxes": {
"square": { "x": 120, "y": 120, "width": 80, "height": 80 }
},
"tracks": [
{
"targetUid": "square",
"property": "rotate",
"keyframes": [
{ "time": 0, "value": 0 },
{ "time": 0.5, "value": 90 },
{ "time": 1, "value": 180 },
{ "time": 1.5, "value": 270 },
{ "time": 2, "value": 360 },
{ "time": 2.5, "value": 360 },
{ "time": 3, "value": 270 },
{ "time": 3.5, "value": 180 },
{ "time": 4, "value": 90 },
{ "time": 4.5, "value": 0 }
]
},
{
"targetUid": "square",
"property": "anchor",
"keyframes": [
{ "time": 0, "value": "1 1" },
{ "time": 0.5, "value": "1 0" },
{ "time": 1, "value": "0 0" },
{ "time": 1.5, "value": "0 1" },
{ "time": 3, "value": "0 0" },
{ "time": 3.5, "value": "1 0" },
{ "time": 4, "value": "1 1" }
]
}
]
}property: "anchor"- Keys the pivot, in place of the target's
pivotsentry. It needs a move, turn, scale or skew track on the same target: on its own it plays nothing, and nothing is noted inprogram.skipped. valuenumber | stringrequired- Two fractions of the box in a string,
"ax ay"(a comma works too)."0.5 0.5"is its middle. A value it can't read, such as a lone number, is left out and noted inprogram.skipped. timenumberrequired- Seconds: from here on, it turns about this point. The first keyframe holds from the start.
easingstringoptional- Not read: a switch is a step.
Several players on one element
Players and pointer actions that share a stage can move the same element. The stage keeps one transform for it and adds them up: moves add, turns add, skews add, stretches multiply. Exclusive drawers are the exception: of the drawers made with svgDrawer's exclusive option on one element, each part (move x, move y, turn, skew, stretch) comes from the last of them to draw that part. What is not exclusive still adds.
Turn, skew and stretch each happen about one pivot: that of the last one to join that moves that part and, when it last drew, had it away from rest (a turn or skew other than 0, a stretch other than 1). A clip still on its first frame, unturned, has no say. One joined through ranked(stage, rank) with a higher rank counts as later, however late the other joined. So a bounce can stretch on its bottom edge while a spin turns about the middle.
The Clocks and the stage page shows a shared stage at work.
ranked(stage, rank)Stage- The same stage, for sources of rank
rank: each one joined through it comes after every source ranked lower, so its pivot wins. Sources joined straight on the stage have rank0.
Reference
pivotsRecord<string, StewPoint>default 0, 0- Where each target turns, scales and skews about, in the units of the element its transform is written to (for the outermost
<svg>, a share of its box). boxesRecord<string, StewBox>optional- Each target's own box, for its
anchortrack. Without one, the track is left out and noted inprogram.skipped.
xnumberrequired- Across.
ynumberrequired- Down.
x, ynumberrequired- Its left top corner, in its own units.
width, heightnumberrequired- Its size, in the same units.
matrix[number, number, number, number, number, number]optional- (a, b, c, d, e, f) from the box's units into the units of the element its transform is written to. Without it, they are the same units.