Interactive states
A graphic can be a live UI element: its timeline cut into named states that page events and your code switch between. The same item renders to video for a product film.
Button
Hover it, then click it.
…Toggle
Click to switch it.
…Like
Click to like, again to unlike.
…Loader
Your code decides how it ends.
…Notification bell
Hover to ring it, click to clear.
…These are the five items in the UI pack, each in a <volito-player>. Each one declares its own states, so they work with no setup: the player plays each state's stretch of the timeline, loops the idle ones and moves on by itself (press hands on to loading). Your code switches the rest.
Use one
<script type="module" src="https://cdn.jsdelivr.net/npm/volito/dist/player.js"></script>
<volito-player item="ui/button" aspect="1000x500" ground="none" brand="studio"
props='{"label":"Get started"}'></volito-player>
<script type="module">
const button = document.querySelector("volito-player");
button.addEventListener("statechange", (e) => console.log(e.detail.to)); // enter → idle → hover → press → loading
await fetch("/api/signup", { method: "POST" });
button.state = "done"; // lands on the check
</script>| What it does | |
|---|---|
state | The state it is in. Set it to switch: player.state = "done". The attribute sets the first one. |
setState(name) | The same, as a promise that settles once the state has started. |
stateDefs() | The states it has, resolved from the item and the attribute. |
statechange | An event on every switch, with { from, to } in its detail. |
States on any graphic
Any graphic can have states, not only the UI pack. The states attribute cuts its timeline, and on maps page events to them:
<!-- Waits empty; every click stamps it again. -->
<volito-player item="annotate/stamp" props='{"text":"Approved"}'
states='{
"ready": { "from": 0, "play": "hold" },
"stamp": { "from": 0, "to": "end", "play": "once" }
}'
on="click: stamp"></volito-player>| Field | What it takes |
|---|---|
from | Where the stretch starts: seconds, one of the item's beat names, start or end. A negative number counts from the end. The start by default. |
to | Where it ends, the same way. The end by default. |
play | once plays it and stays on its last frame, loop repeats it, hold shows from and stays. |
next | The state to go to when a once stretch finishes. |
on takes event: state pairs separated by ;. A guard in brackets limits a pair to some states: pointerenter(idle|unhover): hover only hovers from idle or on the way back. Any DOM event on the element works: pointerenter, pointerleave, click, focus, blur, pointerdown, pointerup.
It starts in the state you ask for, else enter (an entrance that hands on), else idle, else the first one.
In your own items
An item declares its states in item.json, next to its beats, so every player that shows it gets them. Name the beats after the moments, and the states read like the design:
{
"beats": { "idle": 0.6, "hoverIn": 1.6, "hoverOut": 1.9, "press": 2.2, "loading": 2.6, "done": 3.6 },
"states": {
"enter": { "from": "start", "to": "idle", "play": "once", "next": "idle" },
"idle": { "from": "idle", "to": "hoverIn", "play": "loop" },
"hover": { "from": "hoverIn", "to": "hoverOut", "play": "once" },
"unhover": { "from": "hoverOut","to": "press", "play": "once", "next": "idle" },
"press": { "from": "press", "to": "loading", "play": "once", "next": "loading" },
"loading": { "from": "loading", "to": "done", "play": "loop" },
"done": { "from": "done", "to": "end", "play": "once" }
},
"on": "pointerenter(idle|unhover): hover; pointerleave(hover): unhover; click(idle|hover|unhover): press"
}Volito checks them when it loads the item, so volito check, and every other command, stops on a state that names a beat the item does not have, a next that is not a state, or an on pair that points nowhere. Write your own has the rest of the item format.
The same item as video
States are for a page. A render plays the whole timeline, enter to done, so the button that lives in your sign-up form also renders into the launch video, in the same brand:
volito render ui/button --prop label="Get started" --style studio --format webm --out button.webmReduced motion
For readers who prefer reduced motion, looping states hold their first frame and a once state shows its last frame at once, then moves on to next. Every state still reads; nothing moves on its own.