Exports
An animated download from Stew Factory is its artwork, its scene data and one call that plays them: `mount`. This page shows that call and the handle it gives back.
What a download is
Every animated download carries the same three things, in React, Vue, Angular or as a Web Component. Only the code around them changes.
mount comes from the runtime: Stew Engine, plus the code that wires a scene together in Stew Factory's previews (its start, its clips, its wires), in one file that imports nothing. So a download moves as the preview does. Its bundle test holds it to 45 KB gzipped.
A design with no animation yet downloads as plain markup, with no runtime at all.
<svg>- The artwork. It keeps the
data-stew-*attributes the runtime reads: which element is which (data-stew-uid), its anchor, its layers. SCENE- Plain JSON: the scene's clip, the clips that events and data play, and the wires between them.
mount(svg, SCENE)- Plays the scene on the artwork, and hands back its player,
setanddestroy.
Mount a scene
This SCENE is written by hand in the shape an export writes, and mounted on the artwork with the runtime's own mount, as a download does it. Each button calls the handle mount returns. stew.destroy() puts the artwork back as it was drawn, and the same button then mounts it again.
The scene's clip repeats, so reverse() winds back through every lap it has played. The demo hands the data clip false as it mounts, so false does nothing until true has played: the same value twice is no change.
{
"v": 1,
"doc": {
"duration": 1.4,
"tracks": [
{
"targetUid": "friend",
"property": "y",
"keyframes": [
{ "time": 0, "value": 0, "easing": "power2.out" },
{ "time": 0.45, "value": -64, "easing": "power2.in" },
{ "time": 0.9, "value": 0 }
]
},
{
"targetUid": "friend",
"property": "scaleX",
"keyframes": [
{ "time": 0.9, "value": 1, "easing": "power2.out" },
{ "time": 1, "value": 1.16, "easing": "back.out(3)" },
{ "time": 1.4, "value": 1 }
]
},
{
"targetUid": "friend",
"property": "scaleY",
"keyframes": [
{ "time": 0.9, "value": 1, "easing": "power2.out" },
{ "time": 1, "value": 0.82, "easing": "back.out(3)" },
{ "time": 1.4, "value": 1 }
]
},
{
"targetUid": "shadow",
"property": "scale",
"keyframes": [
{ "time": 0, "value": 1, "easing": "power2.out" },
{ "time": 0.45, "value": 0.55, "easing": "power2.in" },
{ "time": 0.9, "value": 1 }
]
}
],
"trigger": "load",
"loop": true
},
"interactions": [
{
"id": "happy",
"name": "Happy",
"binding": { "kind": "boolean", "name": "happy" },
"doc": {
"duration": 0.5,
"tracks": [
{
"targetUid": "heart",
"property": "opacity",
"keyframes": [
{ "time": 0, "value": 0 },
{ "time": 0.12, "value": 1 }
]
},
{
"targetUid": "heart",
"property": "scale",
"keyframes": [
{ "time": 0, "value": 0.3, "easing": "back.out(2.5)" },
{ "time": 0.5, "value": 1 }
]
},
{
"targetUid": "cheeks",
"property": "opacity",
"keyframes": [
{ "time": 0, "value": 0 },
{ "time": 0.5, "value": 1 }
]
}
]
}
}
]
}The scene data
Stew Factory writes SCENE on every animated export, as JSON on one line next to the markup. It is generated data for the runtime, not for editing by hand: the next export writes it again.
Its doc is the scene's clip in the format Stew Factory saves, which is the format Stew Engine reads, plus what starts it and whether it repeats.
vnumberrequired- The data version, 1 today.
mountthrows on any other, so data from a newer Stew Factory asks for a newer runtime. docobjectrequired- The scene's clip, with its
triggerandloop, and the shapes' own actions (behaviors). interactionsreadonly object[]optional- The clips an event, a wire or the app's data plays, each a clip of its own.
chainobjectoptional- The wires between those clips, and when each scene clip starts and ends.
trigger"load" | "click" | "hover" | "inview" | "scrollscrub"default "load"loadplays at once.clickreplays it on every click on the host.hoverplays while the pointer is over the host and winds back when it leaves.inviewplays once 30% of the host is in view.scrollscrubfollows the scroll.loopbooleandefault true- Repeat when it ends. A scroll scrub never repeats.
The call and its handle
mount draws the scene's first frame at once (a scroll scrub: where the scroll has it), then its trigger starts it. The shapes' own actions play from the start, whatever starts the scene.
The handle's player is a Stew Engine player, so the calls on the player page work on it. mount sets its repeat from the scene's loop: -1 when it repeats, 0 when it doesn't. Take the scene down with stew.destroy(), not player.destroy(): that stops only the scene's clip.
svgSVGSVGElementrequired- The artwork the scene was exported with. Each target is found by its
data-stew-uid. sceneStewScenerequired- The
SCENEexported with it. options.hostElementdefault the svg- What a click, hover or in-view start listens on.
options.scrollerElement | nulldefault the page- What scrolls the host, for an in-view start or a scroll scrub.
options.controlbooleanoptional- With
host: the host is a control wrapping the artwork (a button, a link, the label of a checkbox or text field). The whole component's clips listen on it, and while it is disabled the pointer starts nothing and its clicks are eaten, as with a disabled<button>. Clips the app's data plays still play.
playerPlayer- The scene's clip:
play(),pause(),reverse(),restart(),seek(),timeScaleand the rest. set(kind, name, value)- Feeds a data clip what the app passes, by its name.
destroy()- Stops everything and puts the artwork back exactly as it was.
Feeding it data
A clip can be driven by the app's data instead of an event. Each framework's file turns those clips into props (inputs in Angular, attributes or properties on the Web Component) and hands every change to set. A framework file keeps set to itself and takes props. When you call mount yourself, call set directly.
The same value twice is no change, as with a prop set to what it was. A name no clip answers to does nothing.
"state"string- The value names the state, and its clip plays from the start.
setdoes not read the name for a state (the framework files pass"state"):set("state", "state", "error"). "value"number- Glides the clip's playhead to that share of it, 0 to 1, over 0.35 seconds, easing out. A newer number takes over. Outside 0 to 1 it stops at the ends.
"boolean"boolean- The first value snaps into place without playing, so a component mounted already on doesn't animate itself on. After that,
trueplays the clip forward andfalseplays it back.
In each framework
Each file mounts the scene once its artwork is in the page and destroys it when it leaves. Each hands you the handle's player, which is null until the scene is mounted.
A Button, Link, Checkbox or Input download wraps the artwork in that control (a button, a link, or a label holding a native checkbox or text field), and mounts with that wrapper as host and control: true.
The files import mount from @stew-engine/player. That runtime is not on npm yet, so for now there is nothing to install.
React- Mounts in a layout effect, before the first paint, and destroys on unmount. With
ref={anim}:anim.current?.player. Vue 3- Mounts in
onMountedand destroys inonBeforeUnmount. Withref="anim":anim.value.player. Angular- Mounts in
ngAfterViewInit, in the browser only and outside Angular's zone, and destroys inngOnDestroy. With@ViewChild:anim.player. Web Component- Mounts in
connectedCallbackand destroys indisconnectedCallback. On the element:el.player.