# dotlottie-web: a Rust and WASM Lottie player for the browser

> dotlottie-web is the LottieFiles web player, a Rust and WASM core built on the ThorVG vector renderer with Software, WebGL2 and WebGPU backends, plus first-party SDKs for React, Vue, Svelte, Solid and Web Components. The interesting engineering is the off-main-thread rendering path and the dotLottie v2 format features that need no JavaScript glue.

**LottieFiles/dotlottie-web** — High-performance Lottie & dotLottie web player powered by Rust + WASM, with React, Vue, Svelte, Solid & Web Components.

- Repository: https://github.com/LottieFiles/dotlottie-web
- Website: https://lottiefiles.com/dotlottie
- Stars: 939 · Forks: 59
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/lottiefiles-dotlottie-web

## One player for two animation formats

dotlottie-web is the official LottieFiles player for Lottie and dotLottie animations on the web. The distinguishing feature is that the same player handles both formats: you point src at a classic Lottie .json file or at a .lottie archive and nothing else changes.

The .lottie format is the compressed archive that bundles multiple animations, themes, state machines and embedded assets into a single file. The README calls that first-class support for dotLottie v2, covering theming, state machines and audio, with no userland wiring required. In other words, the features that a .json file simply cannot express travel inside the archive instead of being reconstructed in your application code.

The audience is any web team that ships motion graphics. The homepage is the dotLottie product page on lottiefiles.com, the documentation lives on the LottieFiles developer site, and the README links a Live Viewer and a Perf Playground hosted on GitHub Pages, so you can look at a running player and at a benchmark harness without writing anything.

The player is the same engine that ships in the iOS and Android and native dotLottie players, built on dotlottie-rs. That is the strategic point of the project: one implementation in Rust across platforms, with the web build compiled to WebAssembly, rather than a JavaScript reimplementation that drifts from the mobile behaviour.

## Three rendering backends behind one class

The rendering core is ThorVG, which the README describes as an industrial-grade vector graphics engine with the broadest Lottie feature coverage of any web renderer, and links to a ThorVG Lottie support matrix.

Above it there are three backends: Software using Canvas2D, WebGL2, and WebGPU, which the README marks as experimental. The switching mechanism is described as a one-line import change with the same DotLottie class everywhere. That is a significant design choice, because it means application code does not branch on the renderer, and a team can move from the safe Canvas2D path to WebGPU without touching call sites.

The backends differ in what they cost and what they can do. Canvas2D is the baseline and works everywhere. WebGL2 is what a performance-minded team will pick for many simultaneous animations, because it batches drawing work through the GPU rather than through the 2D context. WebGPU is the newest path and the one the README marks experimental, which means the API surface around it may still change.

The runtime control surface is also large, and it is the part that decides whether this player fits a design system. The README lists themes, slots covering color, scalar, vector, gradient, text and image types, markers, segments, layouts with fit and align, playback modes of forward, reverse and bounce, frame interpolation, and more than 25 typed events. Slots in particular are the mechanism that lets a designer expose a colour or an image as a named handle that your code changes at run time, without re-exporting the animation from After Effects.

## The worker path keeps animation off the main thread

The rendering model has two shapes, and the second one is the more interesting.

The straightforward path constructs the player against a canvas element in the page:

```js
import { DotLottie } from '@lottiefiles/dotlottie-web';

const dotLottie = new DotLottie({
  canvas: document.getElementById('canvas'),
  src: 'https://your-animation-url.lottie',
  autoplay: true,
  loop: true,
});
```

The alternative is DotLottieWorker, which the README says renders on a Web Worker with OffscreenCanvas, keeping your interface smooth even with dozens of animations. The move of the canvas into a worker is the whole trick: the animation runs on its own thread, and the main thread is left to handle input and layout.

This matters more as animations multiply. A page with a single decorative loop is not a problem. A dashboard, an onboarding flow or a product page with a dozen animated elements will consume main thread time proportional to the number of canvases, and that time is time your scroll, your clicks and your layout have to compete for. Offloading removes that contention rather than reducing it.

The constraint is that OffscreenCanvas support is not universal in older browsers, so a project with a broad browser support matrix has to decide which path is the default and what the fallback is. The README does not spell out a fallback table, which is worth checking before you commit.

## Six SDKs, one class and one install command

The framework packages are first-party and all follow the same shape. Vanilla JavaScript installs the core package:

```bash
npm install @lottiefiles/dotlottie-web
```

React has its own wrapper, DotLottieReact, and its own package name:

```bash
npm install @lottiefiles/dotlottie-react
```

and the component takes the same src, loop and autoplay props.

The full set covers Vanilla JS, React, Vue, Svelte, Solid and a Web Component, and the README notes SSR-safe usage with a Next.js example included, plus Node.js 18 and above support. The Web Component is the interesting one for teams without a build step, because it works from a plain script tag:

```html
  <dotlottie-wc
    src="https://lottie.host/4db68bbd-31f6-4cd8-84eb-189de081159a/IGmMCqhzpt.lottie"
    autoplay
    loop
  ></dotlottie-wc>

  <script
    type="module"
    src="https://unpkg.com/@lottiefiles/dotlottie-wc@latest/dist/dotlottie-wc.js"
  ></script>
```

That script tag points at the latest tag on a CDN. For a production deployment you would pin the version rather than tracking latest, since an unpinned dependency is a change you did not make landing in your bundle.

The SDK split is the practical benefit. The wrappers are thin, and the wrappers are where framework-specific conventions live, which means an animation that ships on the marketing site and one that ships in the app can share the same .lottie file and differ only in the component they are wrapped in.

## State machines and theming without JavaScript glue

The dotLottie v2 features are the reason to prefer this player over a generic Lottie renderer, and the README demonstrates them concretely.

State machines are built into the file format. You define states, transitions and inputs in a single .lottie and drive them at run time through pointer events, custom events or input values:

```js
const dotLottie = new DotLottie({
  canvas: document.getElementById('canvas'),
  src: 'interactive-button.lottie',
  stateMachineId: 'main',
  autoplay: true,
});
```

The player then exposes typed events for stateMachineStart, stateMachineTransition and stateMachineStateEntered, along with custom events and input changes. That is what makes an animated button interactive without a pile of frame-range comparisons.

Theming works the same way. You can switch to a theme defined in the .lottie manifest, or supply a theme object at run time:

```js
// Use a theme defined in the .lottie manifest
dotLottie.setTheme('dark');

// Or supply a theme object at runtime
dotLottie.setThemeData({
  rules: [
    { id: 'primary', type: 'Color', value: [0.9, 0.2, 0.4, 1.0] },
  ],
});
```

The Theme type covers color, scalar, position, vector, gradient, image and text rules, all of them keyframe-aware. The point for a product team is that one animation file can ship in a light and a dark theme without two exports, and the values can be driven from a single source of truth in your design tokens.

Audio is the third piece. A .lottie file can carry embedded audio tracks alongside the animation timeline, which the README positions for UI sound effects and onboarding flows.

## The monorepo: turbo, changesets, biome and a size budget

The repository is a pnpm workspace built on turbo, with the packages under packages/ and the runnable apps under apps/. The root package.json is marked private and named @lottiefiles/dotlottie-web-monorepo, and the build scripts filter by directory:

```json
  "scripts": {
    "build:packages": "turbo run build --filter='./packages/*'",
    "build:apps": "turbo run build --filter='./apps/*'",
    "build:examples": "turbo run build --filter='./examples/*'",
    "build": "turbo run build",
  }
```

The release process is changesets based. There is a changelog script that adds an entry and a changelog check that runs changeset status against main, and publishing is a clean, a package build and changeset publish. That is a well-trodden pattern for a monorepo that ships several packages with independent version numbers, and it is why the release list shows separate versions for the web, web component and Vue packages on the same day.

Two details are worth copying. There is a size-limit configuration, and a size script that runs it, so the shipped bundle size is treated as a budget that fails the build rather than a number nobody watches. And the test command runs vitest in a headless browser rather than in Node, which is the only way to test a WebGL renderer, a Web Worker and OffscreenCanvas.

The repository also carries a .gitmodules file and a SKILL.md, and the examples directory holds one project per target: next, react, solid, vue, wc, web and web-node. The last of those, web-node, exists because the player has to run under Node for server-side rendering, which is exactly the case a canvas renderer usually breaks.

## Conclusion

dotlottie-web suits a team shipping Lottie or dotLottie animations on the web that needs one player across frameworks, wants rendering off the main thread, and needs the dotLottie v2 features such as state machines, theming and audio without wiring them by hand. It does not suit a project that only needs a single small icon animation, where the WASM payload is overhead, and it does not suit a team that cannot ship a WebAssembly asset. Before adopting, install @lottiefiles/dotlottie-web, render one animation with each backend you plan to support, and check the size-limit budget the repository enforces, since the WASM core is the dominant part of what you ship.

## FAQ

### What is dotlottie-web and which formats does it play?

It is the official LottieFiles web player for Lottie .json files and dotLottie .lottie archives. The same DotLottie class loads either format, with dotLottie v2 support for theming, state machines and audio.

### Which rendering backends does dotlottie-web support?

Three: Software using Canvas2D, WebGL2, and WebGPU, which the README marks as experimental. The renderer is chosen with a one-line import change and the same DotLottie class is used everywhere.

### How do I install and use the dotlottie web player?

Run npm install @lottiefiles/dotlottie-web, put a canvas in the page, and construct the player with the DotLottie class, passing the canvas, the src, autoplay and loop. There are also framework packages for React, Vue, Svelte, Solid and a Web Component usable without a build step.

### What does DotLottieWorker change about rendering?

DotLottieWorker renders on a Web Worker with OffscreenCanvas, so the animation does not compete with your interface for main thread time. The README describes this as keeping the interface smooth even with dozens of animations.

### How do state machines work in dotLottie?

State machines are built into the dotLottie v2 file format, so states, transitions and inputs are defined in the .lottie itself. You point the player at the machine with stateMachineId and drive it through pointer events, custom events or input values, and the player exposes typed events such as stateMachineStart and stateMachineTransition.

## Sources

- [License: MIT](https://github.com/LottieFiles/dotlottie-web/blob/main/LICENSE)
- [LottieFiles/dotlottie-web on GitHub](https://github.com/LottieFiles/dotlottie-web)
- [Project website](https://lottiefiles.com/dotlottie)
- [README](https://github.com/LottieFiles/dotlottie-web/blob/main/README.md)
- [Releases](https://github.com/LottieFiles/dotlottie-web/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lottiefiles-dotlottie-web
