Skip to content

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.)

  1. 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
  2. Installing the players — npm packages, the UMD build for pages without a bundler, TypeScript
  3. Web player (@pixodesk/svg-animator-web) — createSvgAnimationPlayer, the playback API, callbacks, triggers, the API reference
  4. React (@pixodesk/svg-animator-react) — the player component, its props, control modes
  5. Next.js — the React component in a Next.js app
  6. Vue (@pixodesk/svg-animator-vue) — the player component, props, events
  7. Nuxt — the Vue component in a Nuxt app
  8. React Native (@pixodesk/svg-animator-rn) 🧪 — in development; install, props, feature support, limitations
  9. Playback settings & triggers — the animator configuration, and overriding it from props or the player API
  10. Minification & property mangling — safe by default; what to do if your build renames object keys
  11. 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.

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.

JobCall
Play a JSON file in a pagecreateSvgAnimationPlayer({ src, container }) (web)
Play it in React / Vue<SvgAnimationPlayer :doc … />
Play it in React Native<SvgAnimationPlayer doc={…} /> (rn)
Check a generated document before shipping itvalidateDocument(doc)
Show the same JSON animation twice on one pagenothing extra — every player gives each render fresh ids (generateNewIds(doc) is for a renderer of your own)
Feed a renderer of your ownmaterializeAllInTree(doc, 'native') (core)
See or drive every player on the page — 🧪 experimentalgetAllSvgAnimationPlayers() / onSvgAnimationPlayersChange() (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.

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 createSvgAnimationPlayer (Web), the HTML tag read by createSvgAnimationPlayersFromPage (Tag), the pre-rendered player’s createSvgAnimationPlayer (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.

NameWebTagPreReactVueRN
Document
src✓1————
doc✓—2✓✓✓
container✓3————
Playback override
timelineOptions✓——✓✓4
actions✓——✓✓✓
Play using action triggers
playUsingActionTriggers✓1011✓✓5
Declarative control
play———✓✓✓
pause———✓✓✓
showAtProgress———✓✓✓
showAtTime———✓✓✓
Imperative control
playerRef676✓8✓
Callbacks
onPlay✓—✓✓@play✓
onPause✓—✓✓@pause✓
onReset✓—✓✓@reset✓
onFinish✓—✓✓@finish✓
onReady✓—✓✓@ready✓
onDestroy✓—✓✓@destroy✓
onStop✓—✓✓@stop✓
onError✓—✓✓✓✓
onWarn✓—✓✓✓✓
suppressWarnings✓—✓✓✓✓
suppressErrors✓—✓✓✓✓
fallback—————✓
Styling
className———✓9—
style———✓✓—

Notes

  1. The tag takes the URL as the data-px-animation-src attribute.
  2. Required. Only animator.definitions and animator.bindings are needed: the SVG itself is already in the page.
  3. The tag is the container: the player renders into the element that carries the attribute.
  4. React Native ignores engine and frameRate inside timelineOptions.
  5. true, or the whole actionTriggers block to use instead of the file’s (a PxActionTriggers); React Native ignores hoverIn / hoverOut, which have no touch equivalent.
  6. The handle is what createSvgAnimationPlayer returns, a PxAnimationPlayerApi.
  7. createSvgAnimationPlayersFromPage returns the handles it created; getSvgAnimationPlayer(element) finds one later.
  8. The handle is the component’s template ref, a PxAnimationPlayerHandle.
  9. Written class; like style, it falls through to the root <svg>.
  10. The tag always plays on the file’s own triggers — embedding a finished file IS choosing its behaviour — so it takes no playUsingActionTriggers option.
  11. true only: a pre-rendered file plays on its own triggers, or on the returned api.

What some of the names mean:

  • src is 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.
  • doc is 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 calls createSvgAnimationPlayer({"doc": …}) (PX_ANIMATOR_DOC_KEY), so it is never renamed by a minifier.
  • container left out means: animate an SVG that is already in the page.
  • timelineOptions merges corrections over the file’s timing block — { iterations: 'infinite' }, { playDuration: 500 } — never a replacement; null at a key deletes it. See Overriding from a player.
  • actions merges over the file’s timeline.actions — how start, stop, finish and out-of-view look: { stop: 'rewind' }. The same rules as timelineOptions.
  • playUsingActionTriggers means “play the way the document says”. The HTML tag always works this way; the web player takes it as an option (createSvgAnimationPlayer({ …, playUsingActionTriggers: true })) — without it, nothing starts and the returned api drives playback. An object instead of true is the whole actionTriggers block to use in place of the file’s ({ start: 'hoverIn', stop: 'hoverOut' }).
  • play is the on/off switch: true calls the built-in start, false the built-in stop, each done the way the file’s actions say (the presets, the stop’s completeIteration — Actions). play={false} performs the stop action (actions.stop: reset or rewind) — it does not pause; freeze with pause, which holds the current frame until it is set back to false.
  • showAtProgress shows the frame at a point between 0 and 1 of the whole run (of one iteration when iterations is 'infinite'); showAtTime shows the frame at that many ms from the start.
  • playerRef is the handle for calling play(), pause(), stop() and the rest from your code. Having it never changes how the component is controlled.
  • onDestroy fires when the player is thrown away: destroy(), an unmount, or a new doc. onStop fires when the built-in stop action is performed — not on a pause (onPause), the end (onFinish) or a removal (onDestroy).
  • onError means this player will not play: the document failed to load, parse or build, or drawing it threw. Nothing is rendered, isReady() is false, and React Native shows fallback instead. Without a handler the message goes to console.error.
  • onWarn means it plays, but something was ignored, simplified or misspelled. Without a handler the message goes to console.warn.
  • suppressWarnings / suppressErrors turn off those console messages, for an app that already knows about them. A handler you passed still gets called.
  • className and style style the root <svg>. On the web, style the container instead.

The pre-rendered SVG + CSS wrappers toggle class names instead of creating a player:

NameReact SvgCssAnimationPlayerVue SvgCssAnimationPlayer
the SVGchildrendefault slot
actionTriggers✓ the file’s actionTriggers block; absent = plays on load✓ same
actions✓ outOfView only; default 'pause'✓ same
inViewThreshold✓ default 0.5✓ same
inViewDebounce✓ default 150 ms✓ same
className✓ on the wrapper divclass, on the wrapper div
style✓ on the wrapper div✓ on the wrapper div
  • actionTriggers is the JSON player’s block — start, stop, pause (the derived resume follows), each one event or a list of them, read by the same rules (Triggers): pause: 'hoverOut' pauses, stop: 'hoverOut' stops. An empty block does nothing here: a wrapper has no play() to call.
  • actions takes only outOfView ({ outOfView: 'pause' }): an animation nobody can see does not run, whatever started it.
  • Accepted limits of a class toggle: a start acts as the continue preset and a stop as reset — a class cannot restart keyframes, jump to their end or play them backwards — and the stop’s completeIteration, showWhenStopped and the finish preset are the file’s own CSS. None of them is a prop here.
  • inViewThreshold is how much of the SVG (0 to 1) must be on screen before it may run; inViewDebounce is how long it must stay that way first, so scrolling straight past starts nothing. The defaults are the same as the JSON player’s.

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:

PriorityModeChosen whenThe document’s triggers
1controlled timeshowAtProgress or showAtTimeswitched off; the player seeks and holds
2play / pauseplay or pauseswitched off; play={true} calls start, play={false} performs the stop action (actions.stop: reset or rewind) — it does not pause — and pause freezes
3playUsingActionTriggersplayUsingActionTriggersused, after the override
4staticnone of the aboveswitched off; the first frame renders and nothing plays

playerRef is not in the table: the handle is filled in every mode and never changes it, so <SvgAnimationPlayer doc={doc} playUsingActionTriggers playerRef={playerRef} /> autoplays and gives you the handle. playUsingActionTriggers: false is not a control prop and claims nothing; play: false is one, and holds. The HTML tag is always in playUsingActionTriggers mode; the web player’s playUsingActionTriggers: true option is the same mode.

The callbacks have the same names on every player: you pass them as options on the web (createSvgAnimationPlayer({ 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 PxAnimationPlayerCallbacks:

// 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 `createAdapterSvgAnimationPlayer` takes) → `PxAnimationPlayerCallbacks` (+ `onStop`; what every
// player takes).
interface PxAnimationPlayerCallbacks {
onReady?: () => void; // the player exists and the SVG is rendered — once, async;
// the push twin of isReady()
onPlay?: () => void; // started or resumed
onPause?: () => void;
onReset?: () => void;
onFinish?: () => void; // reached the end, or finish() was called — not when stopped early
onDestroy?: () => void; // destroy() was called, the component unmounted, or a new `doc` arrived
onStop?: () => void; // the built-in stop was performed (now, or after the iteration it waited for)
// 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
suppressWarnings?: 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: this is about the console, not you
suppressErrors?: 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:

kindwho fixes itexamples
documentregenerate or repair the fileeffects shape, unknown keys, an invalid document, no or unresolved bindings, a scroll.subject that is not a valid selector, a blocked SVG tag
hostfix the page or appno root element, a selector that matched nothing, setAttribute finding no element, a failed fetch
platformnothing — the player degradedunsupported CSS attrs, smoothing needing the built-in driver, native scroll-timeline construction failing, react-native-svg prop limits
usagefix the options or props you passedprops from more than one control mode at once, an override that could not apply, a rate of 0, actionTriggers on a scroll timeline
internalreport it to uscould 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.

Every engine on every player implements the same meaning of time, written on PxAnimationPlayerApi 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 when iterations is 'infinite';
  • a rate of 0 is rejected everywhere, with a warning — pause() is how you stop;
  • showAtProgress and getCurrentProgress() 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.

The file’s own keys are explained on the JSON format page; these are the props and calls of the players:

NameWhy
docnot document: document shadows window.document in exactly the files that also query it, and the type is PxDocument
playerRefnot React’s ref: the handle is not a control mode — the drivers are the play… / show… props — and Vue and React Native carry the same name, so one word reads the same in all three
playUsingActionTriggersa driver prop starts with its verb and says what drives — here the action triggers; autoplay lied for a click file (it waited), triggers alone did not say that it plays
play / pausetwo booleans, not a state word: play is on / off and pause a freeze on top — the CSS model (animation-name applied × animation-play-state), so play={hovered} and pause={!inView} compose
showAtProgress / showAtTimeshow… because they show a frame and never play; ms as every time on this API (WAAPI’s unit), so not showAtMs
timelineOptionsnot timeline: it is not the file’s timeline object — two of its keys live on other props — and a prop sharing a file key’s name would promise the same shape; actions keeps the file’s name because it is a partial of that block
suppressWarnings / suppressErrorsReact’s own suppressHydrationWarning / suppressContentEditableWarning set the word; muteWarn / muteError until 1.15
onFinishWAAPI’s word (finish(), onfinish, playState: 'finished'), one trio with the finish moment in actions and the finished state; ended is <video>’s, complete Lottie’s
onReset / onStopa state against an action: onReset says “back at the start pose”, whatever caused it; onStop says “the stop action was performed”
getDuration()one iteration, as WAAPI’s duration, CSS animation-duration and lottie-web’s getDuration() are; × iterations for the whole run