Library documentation — the players
How to install and use the player libraries that render and control JSON animations: plain HTML, React, Vue and React Native, plus the playback settings and triggers they all share. (Playing a pre-rendered SVG needs no library — see Pre-rendered SVG documentation.)
Contents
Section titled “Contents”- Get started with the player library — the shortest path, end to end: save a JSON, put it next to your component, install one package, render it; a complete example project per stack
- Installing the players — npm packages, the UMD build for pages without a bundler, TypeScript
- Web player (
@pixodesk/svg-animator-web) —createAnimator, the playback API, callbacks, triggers, the API reference - React (
@pixodesk/svg-animator-react) — the player component, its props, control modes - Next.js — the React component in a Next.js app
- Vue (
@pixodesk/svg-animator-vue) — the player component, props, events - Nuxt — the Vue component in a Nuxt app
- React Native (
@pixodesk/svg-animator-rn) 🧪 — in development; install, props, feature support, limitations - Playback settings & triggers — the
animatorconfiguration, and overriding it from props or the player API - Minification & property mangling — safe by default; what to do if your build renames object keys
- Troubleshooting & FAQ — nothing plays, React/TypeScript/React Native gotchas, playback behavior
Below is what every player has in common — the same props under the same names, the same callbacks, the same rule for who controls playback, the same meaning of time — so what you learn on one player works on all of them. Each guide then spells out its own package in signature form under API reference; the core library’s is on the format page.
The API at a glance
Section titled “The API at a glance”Which package: web for plain HTML/JS · react / vue for those frameworks · rn for
React Native 🧪 · core only to inspect or transform documents yourself. A pre-rendered .svg
file needs no package at all.
| Job | Call |
|---|---|
| Play a JSON file in a page | createAnimator({ src, container }) (web) |
| Play it in React / Vue | <PixodeskSvgAnimator :doc … /> |
| Play it in React Native | <PixodeskSvgAnimator doc={…} /> (rn) |
| Check a generated document before shipping it | validateDocument(doc) |
| Show the same JSON animation twice on one page | generateNewIds(doc) for the second copy |
| Feed a renderer of your own | materializeAllInTree(doc, 'native') (core) |
| See or drive every animator on the page — 🧪 experimental | getAllAnimators() / onAnimatorsChange() (web) |
Every export is marked by audience, in the guides and in the code itself — the mark mirrors the release tag on the declaration, which is what your IDE shows on hover, and the build fails when the two disagree:
| Meaning | |
|---|---|
| ● | User-facing — the API for playing an animation in your page or app. Documented in full. |
| ○ | Advanced — document tooling: inspect, transform or validate a document outside a player. Stable, rarely needed. |
| ▪ | Internal — exported so the Pixodesk editor and the other player packages can share the player’s own code. Not meant for your code; may change without notice. |
Props and options across players
Section titled “Props and options across players”Every way to create a player, side by side, so a prop added or renamed in one place can be
checked against the others. The columns are the web player’s createAnimator (Web), the
HTML tag read by loadTagAnimators (Tag), the pre-rendered player’s createAnimator
(Pre), React, Vue and React Native (RN).
A cell is ✓ when that player takes the name as it is, — when it does not have it, and a number when it differs — the note with that number, under the table, says how.
| Name | Web | Tag | Pre | React | Vue | RN |
|---|---|---|---|---|---|---|
| Document | ||||||
src | ✓ | 1 | — | — | — | — |
doc | ✓ | — | 2 | ✓ | ✓ | ✓ |
container | ✓ | 3 | — | — | — | — |
| Playback override | ||||||
timeline | ✓ | — | — | ✓ | ✓ | 4 |
resetTimeline | ✓ | — | — | ✓ | ✓ | ✓ |
duration | ✓ | — | — | ✓ | ✓ | ✓ |
delay | ✓ | — | — | ✓ | ✓ | ✓ |
iterations | ✓ | — | — | ✓ | ✓ | ✓ |
start | ✓ | — | — | ✓ | ✓ | 5 |
| Autoplay control | ||||||
autoplay | — | — | — | ✓ | ✓ | ✓ |
| Declarative control | ||||||
play | — | — | — | ✓ | ✓ | ✓ |
pause | — | — | — | ✓ | ✓ | ✓ |
progress | — | — | — | ✓ | ✓ | ✓ |
time | — | — | — | ✓ | ✓ | ✓ |
| Imperative control | ||||||
apiRef | 6 | 7 | 6 | ✓ | 8 | ✓ |
| Callbacks | ||||||
onPlay | ✓ | — | ✓ | ✓ | @play | ✓ |
onPause | ✓ | — | ✓ | ✓ | @pause | ✓ |
onCancel | ✓ | — | ✓ | ✓ | @cancel | ✓ |
onFinish | ✓ | — | ✓ | ✓ | @finish | ✓ |
onRemove | ✓ | — | ✓ | ✓ | @remove | ✓ |
onStop | ✓ | — | ✓ | ✓ | @stop | ✓ |
onError | ✓ | — | ✓ | ✓ | ✓ | ✓ |
onWarn | ✓ | — | ✓ | ✓ | ✓ | ✓ |
muteWarn | ✓ | — | ✓ | ✓ | ✓ | ✓ |
muteError | ✓ | — | ✓ | ✓ | ✓ | ✓ |
fallback | — | — | — | — | — | ✓ |
| Styling | ||||||
className | — | — | — | ✓ | 9 | — |
style | — | — | — | ✓ | ✓ | — |
Notes
- The tag takes the URL as the
data-px-animation-srcattribute. - Required. Only
animator.definitionsandanimator.bindingsare needed: the SVG itself is already in the page. - The tag is the container: the player renders into the element that carries the attribute.
- React Native ignores
timeline.engine. - Every player takes every
PxTriggerStartvalue; React Native ignores'mouseOver', which has no touch equivalent. - The handle is what
createAnimatorreturns, aPxAnimatorApi. - The handle is on the element, as
element._px_animator. - The handle is the component’s template ref, a
VueAnimatorApi. - Written
class; likestyle, it falls through to the root<svg>.
What some of the names mean:
srcis a URL to fetch the document from. The components take the document itself on purpose: in a component tree the document is data your app already has (imported, or fetched with your own loader), and fetching inside the component would add a second loading and error state to manage.docis the document itself, under the same name on every player. On the web the name is also part of the export format: every SVG + JS file the editor exports callscreateAnimator({"doc": …})(PX_ANIMATOR_DOC_KEY), so it is never renamed by a minifier.containerleft out means: animate an SVG that is already in the page.autoplaymeans “play the way the document says”. The web player and the tag always work this way.playset tofalseholds the current frame;pauseholds it too, and setting it back tofalseresumes.progressshows the frame at a point between 0 and 1 of the whole run (of one iteration wheniterationsis'infinite');timeshows the frame at that many ms from the start.apiRefis the handle for callingplay(),pause()and the rest from your code. Having it never changes how the component is controlled.onRemovefires when the player is thrown away:destroy(), an unmount, or a newdoc.onStopfires after any of pause, cancel, finish or remove.onErrormeans this player will not play: the document failed to load, parse or build, or drawing it threw. Nothing is rendered,isReady()isfalse, and React Native showsfallbackinstead. Without a handler the message goes toconsole.error.onWarnmeans it plays, but something was ignored, simplified or misspelled. Without a handler the message goes toconsole.warn.muteWarn/muteErrorturn off those console messages, for an app that already knows about them. A handler you passed still gets called.classNameandstylestyle the root<svg>. On the web, style the container instead.
The pre-rendered SVG + CSS wrappers toggle class names instead of creating a player:
| Name | React PixodeskSvgCssAnimator | Vue PixodeskSvgCssAnimator |
|---|---|---|
| the SVG | children | default slot |
start | ✓ default 'load' | ✓ same |
offScreen | ✓ default 'pause' | ✓ same |
mouseOut | ✓ default 'pause' | ✓ same |
visibilityThreshold | ✓ default 0.5 | ✓ same |
visibilityDebounce | ✓ default 150 ms | ✓ same |
className | ✓ on the wrapper div | class, on the wrapper div |
style | ✓ on the wrapper div | ✓ on the wrapper div |
start: 'none'does nothing here: a wrapper has noplay()to call.offScreen: 'pause'means an animation nobody can see does not run, whatever started it.mouseOut: 'reverse'acts like'continue': a class toggle cannot run keyframes backwards.visibilityThresholdis how much of the SVG (0 to 1) must be on screen before it may run;visibilityDebounceis how long it must stay that way first, so scrolling straight past starts nothing. The defaults are the same as the JSON player’s.
Control modes — one rule
Section titled “Control modes — one rule”A component can be controlled in several ways, and only one of them can be in charge. If you set
props from more than one group, the group highest in this table wins, and the player warns you
once, naming the props and the winner. React, Vue and React Native all use the same rule from
core (resolveControlMode), so they always pick the same winner:
| Priority | Mode | Chosen when | The document’s trigger |
|---|---|---|---|
| 1 | controlled time | progress or time | switched off; the player seeks and holds |
| 2 | play / pause | play or pause | switched off; play plays, pause holds, play={false} holds too |
| 3 | autoplay | autoplay | used, after the override |
| 4 | static | none of the above | switched off; the first frame renders and nothing plays |
apiRef is not in the table: the handle is filled in every mode and never changes it, so
<PixodeskSvgAnimator doc={doc} autoplay apiRef={api} /> autoplays and gives you the handle.
autoplay: false is not a control prop and claims nothing; play: false is one, and holds.
The web player and the HTML tag are always in autoplay mode — the document’s own trigger.
Callbacks and diagnostics — one shape
Section titled “Callbacks and diagnostics — one shape”The callbacks have the same names on every player: you pass them as options on the web
(createAnimator({ onFinish })) and as props in React and React Native. Vue takes the playback
ones as events (@play) but onWarn and onError as props — with an event, Vue would always
count the message as handled, and nobody would see it in the console. All of them are defined
once in core, as PxAnimatorCallbacks:
// Every lifecycle callback is optional and takes no arguments. The types build on each other:// `PxDiagnosticsConfig` (the diagnostics fields) → `PxEngineCallbacks` (+ the lifecycle; what an// engine such as `createAdapterAnimator` takes) → `PxAnimatorCallbacks` (+ `onStop`; what every// player takes).interface PxAnimatorCallbacks { onPlay?: () => void; // started or resumed onPause?: () => void; onCancel?: () => void; onFinish?: () => void; // reached the end, or finish() was called — not when stopped early onRemove?: () => void; // destroy() was called, the component unmounted, or a new `doc` arrived onStop?: () => void; // after any of pause / cancel / finish / remove
// Diagnostics — two severities, one meaning each, on every player. Neither ever throws at // the caller. Give a handler and it takes over from the console; give none and the console // is the fallback, so nothing is lost by default. onWarn?: (d: PxDiagnostic) => void; // IT PLAYS, but something was ignored, degraded or // misspelled; else console.warn onError?: (d: PxDiagnostic) => void; // THIS INSTANCE WILL NOT PLAY: failed to load, parse or // build, or the render threw — nothing rendered, // isReady() false, a component shows its fallback; // d.error is the Error; else console.error muteWarn?: boolean; // switch the console.warn fallback off — for a host that // knows the player has something to say about this // document and tolerates it. A handler you passed // still fires: mute is about the console, not you muteError?: boolean; // the same switch for console.error}
// Every diagnostic says WHAT happened as a NUMBER and WHO can act on it, so a host can switch// on the code and route it rather than just log a sentence. The words are not in the build: each// code's description lives on the codes page, generated from the enum the players report through.interface PxDiagnostic { code: PxDiagnosticCode; // e.g. 1304 — look it up on the codes page (docs/diagnostics.md) kind: PxDiagnosticKind; // 'document' | 'host' | 'platform' | 'usage' | 'internal' data?: ReadonlyArray<unknown>; // the values this one had: the offending binding, the // selector that matched nothing, the raw error message: string; // 'PX1304 <link to that code on the codes page>' — the code and // where to read it, never prose and never the console prefix error?: Error; // errors only}Every message comes with a kind that says who can fix it. That is a separate question from
how serious it is: a broken document is fatal, a slightly odd one still plays, but both are the
document’s fault and both are fixed the same way, by fixing the file. So you get one handler per
severity (onError, onWarn) and read kind inside it to decide what to do:
kind | who fixes it | examples |
|---|---|---|
document | regenerate or repair the file | effects shape, unknown keys, an invalid document, no or unresolved bindings, a scroll.subject that is not a valid selector, a blocked SVG tag |
host | fix the page or app | no root element, a selector that matched nothing, setAttribute finding no element, a failed fetch |
platform | nothing — the player degraded | unsupported CSS attrs, smoothing needing the built-in driver, native scroll-timeline construction failing, react-native-svg prop limits |
usage | fix the options or props you passed | props from more than one control mode at once, an override that could not apply, a rate of 0, trigger on a scroll timeline |
internal | report it to us | could not build, compile or render the document; a render that threw |
For example: fail a CI check on document, ignore platform, and send internal to your error
tracker. Filtering on kind is one line in your handler, which is why there is no separate mute
per kind.
Time — one contract
Section titled “Time — one contract”Every engine on every player implements the same meaning of time, written on PxAnimatorApi
and implemented once in core:
- time is ms from the start of the whole run, iterations included — so a slider built on
getCurrentTime()never jumps back when the animation repeats; - a seek clamps to
[0, duration × iterations], unbounded wheniterationsis'infinite'; - a rate of
0is rejected everywhere, with a warning —pause()is how you stop; progressandgetCurrentProgress()are the same position as 0–1 of the whole run — of ONE iteration when endless, since an endless run has no whole to be a fraction of.
See also
Section titled “See also”- Which format do I need?
- Format documentation — the JSON documents the players consume, and the core library
- Documentation home