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

Below, what every player shares — the same props under the same names, one callback shape, one control-mode rule, one meaning of time — so a prop learned on one surface is known 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 pagecreateAnimator({ src, container }) (web)
Play it in React / Vue<PixodeskSvgAnimator :doc … />
Play it in React Native<PixodeskSvgAnimator doc={…} /> (rn)
Check a generated document before shipping itvalidateDocument(doc)
Put one animation on a page twicegenerateNewIds(doc) for the second copy
Feed a renderer of your ownmaterializeAllInTree(doc, 'native') (core)
See or drive every animator on the page — 🧪 experimentalgetAllAnimators() / 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 sibling packages) stay in lockstep with the player. Not part of the supported surface; 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. A cell is ✓ when that surface takes the name as is, shows the spelling when it differs, and is — when the surface does not have it.

NameWeb createAnimatorHTML tag (loadTagAnimators)Pre-rendered createAnimatorReactVueReact NativeNotes
Document
src✓ URLdata-px-animation-src————a URL to fetch the document from. The components take the document itself, on purpose: in a component tree the document is data the app already owns — imported, or fetched with the app’s own loader — and fetching inside the component would mean a second data layer, with its own loading and error states
doc✓—✓ required¹✓ required✓ required✓ requiredthe document, inline — one name on every surface. On the web it also crosses the mangling boundary as a string key: the editor writes createAnimator({"doc": …}) into every exported SVG+JS (PX_ANIMATOR_DOC_KEY), so the key is part of the export format
container✓ selector or Elementthe tagged element————omitted: animate an SVG already in the page
Playback override
timeline✓ object or JSON string——✓✓✓React Native ignores timeline.engine
resetTimeline✓——✓✓✓
duration✓——✓✓✓
delay✓——✓✓✓
iterations✓——✓✓✓
start✓ 4 values——✓ 4 values✓ 4 values✓ 4 valuesevery player surface takes PxTriggerStart (all 4); React Native ignores 'mouseOver'
Autoplay control — the document’s own trigger
autoplay———✓✓✓the web player and the HTML tag are always in this mode: they follow the document’s trigger
Declarative control — your state drives it
play———✓✓✓false holds where it is
pause———✓✓✓hold the current frame; false again resumes
progress———✓✓✓show the frame at 0–1 of the whole run — of ONE iteration when iterations is 'infinite'
time———✓✓✓show the frame at this ms from the start of the whole run
Imperative control — you call it
apiRefthe returned PxAnimatorApielement._px_animatorthe returned PxAnimatorApi✓ — mode unchangedtemplate ref (VueAnimatorApi)✓ — mode unchangedthe imperative handle; never picks a mode on any surface
Callbacks
onPlay✓—✓✓@play✓
onPause✓—✓✓@pause✓
onCancel✓—✓✓@cancel✓
onFinish✓—✓✓@finish✓
onRemove✓—✓✓@remove✓the animator was thrown away: destroy(), unmount, or a new doc
onStop✓—✓✓@stop✓after any of pause / cancel / finish / remove
onError✓—✓✓✓✓THIS INSTANCE WILL NOT PLAY — the document failed to load, parse or build, or the render threw: nothing rendered, isReady() false, fallback shown. Falls back to console.error
onWarn✓—✓✓✓✓IT PLAYS, but something was ignored, degraded or misspelled. Falls back to console.warn
muteWarn✓—✓✓✓✓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 about you
muteError✓—✓✓✓✓the same switch for the console.error fallback
fallback—————✓renders in place of the animation after a failure
Styling
className———✓ on the root <svg>class, falls through to the root <svg>—web: style the container
style———✓ on the root <svg>style, falls through to the root <svg>—

¹ Only animator.definitions and animator.bindings — the SVG is already in the page.

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

NameReact PixodeskSvgCssAnimatorVue PixodeskSvgCssAnimator
the SVGchildrendefault slot
startPxTriggerStart, default 'load' — implements 4; 'none' does nothing (no play() here)✓ same
offScreen✓ default 'pause' — an animation nobody can see does not run, whatever started it✓ same
mouseOut✓ default 'continue'; 'reverse' acts as 'continue'✓ same
visibilityThreshold✓ 0–1 of the SVG that must be on screen before it may run; default 0.5, the wire default✓ same
visibilityDebounce✓ ms it must stay that way first; default 150, so scrolling straight past starts nothing✓ same
className✓ on the wrapper divclass, on the wrapper div
style✓ on the wrapper div✓ on the wrapper div

On the components the three control groups are ONE choice: the highest-priority group that is set wins, a losing group warns once — naming both props and the winner — and React, Vue and React Native resolve it from the same rule in core (resolveControlMode), so they cannot answer it three ways:

PriorityModeChosen whenThe document’s trigger
1controlled timeprogress or timeswitched off; the player seeks and holds
2play / pauseplay or pauseswitched off; play plays, pause holds, play={false} holds too
3autoplayautoplayused, after the override
4staticnone of the aboveswitched 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 are ONE shape everywhere — the names in the table, inline: createAnimator({ onFinish }) on the web, props on React and React Native. Vue takes the lifecycle ones as events (@play) and the diagnostics ones as props — props rather than events because an event handler always exists, which would have silenced the console fallback for anyone who never subscribed. PxAnimatorCallbacks in core is that one shape:

// Every lifecycle callback is optional and takes no arguments. One chain, three levels, each
// extending the one above: `PxDiagnosticsConfig` (the four diagnostics fields) → `PxEngineCallbacks`
// (+ the lifecycle; what an engine such as `createAdapterAnimator` takes) → `PxAnimatorCallbacks`
// (+ `onStop`; what every public surface 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
}

Severity and source are different axes — an invalid document is a document problem and fatal, an effects-shape warning a document problem that still plays — so one channel with a kind replaces four handlers a host would have to wire to hear everything:

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 passedtwo control tiers at once, an override that could not apply, a rate of 0, trigger on a scroll timeline
internalreport it to uscould not build, compile or render the document; a render that threw

So surface document in a CI check, quiet platform, alert on internal. A handler that filters on kind is one line, which is why there is no per-kind mute.

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 when iterations is 'infinite';
  • a rate of 0 is rejected everywhere, with a warning — pause() is how you stop;
  • progress 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.