npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@babylonjs/lottie-player

v10.0.2

Published

Function-based WebGL2 Lottie player with stencil-then-cover vector rendering, text and image layers, and an off-thread Web Worker delivery path.

Readme

@babylonjs/lottie-player

A worker-first WebGL2 vector Lottie player with full JSON and binary animation delivery. Both players render through @babylonjs/lite-gl, a small WebGL2 micro-engine. The full player parses supported Lottie JSON at runtime; the binary player loads a smaller deterministic binary animation whose paths and draw data were prepared at build time.

Dependency. This package depends on the published @babylonjs/lite-gl (its WebGL2 backend) as a normal npm dependency.

Version 10 takeover. Version 10 is a breaking replacement for the experimental v9 player under this canonical npm identity. Existing consumers on @babylonjs/lottie-player@^9 remain on the frozen v9 line; v10 is versioned independently from Babylon.js. The old LocalPlayer sprite-atlas API is replaced by the worker-first vector APIs documented below. The package license changes from MIT in v9 to Apache-2.0 in v10. The canonical source repository is private, while the npm tarball ships this README, the license, declarations, and compiled runtime modules. JavaScript source maps are intentionally excluded so the public tarball neither embeds private TypeScript nor points to source files that are not shipped.


Quick start

All commands run from the repo root:

| Goal | Command | What it does | | --------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | Live viewer | pnpm demo | Builds + serves an interactive viewer at http://localhost:5180. Compare full JSON and binary animation playback in local tooling or a worker. | | Runtime benchmark | pnpm measure | Measures the current renderer with tracked fixtures in headed Chrome and opens a compact report. | | Build the library | pnpm build | Compiles per-module ESM/types and self-contained classic workers into dist/. | | Watch build | pnpm dev | Runs TypeScript in watch mode. |

The two node scripts behind those:

  • node demo/serve.mjs — the live viewer (esbuild watch + dev server).
  • node measure/bench/run.mjs — the current-player runtime benchmark.

CI and npm releases

azure-pipelines-npm-verify.yml runs for pull requests targeting main and pushes to main. It checks formatting, linting and types, unit tests, API documentation, the production build, visual regressions, and the final npm package contents.

azure-pipelines-npm-publish.yml runs the full release validation and publication path when config/release.json changes on main. Set type to patch, minor, or major, increment nonce, and merge the reviewed change to publish from main. Manually queued runs choose the release type in the ADO UI and default to dry-run mode; manual live publication requires dryRun to be explicitly disabled.

The resolver requires the existing canonical npm package, uses the newer of npm latest and the highest npm-lottie-player-v* tag, and rejects unchanged releases, version/tag collisions, any candidate below the source manifest version, and patch/minor releases that contain breaking-change markers. The first standalone release uses an explicit major bump from npm v9 to v10. Publication happens before the matching source tag is created. Because the accidental 11.0.0 publication was withdrawn and cannot be reused on npm, the next major release after v10 skips that exact version and publishes as 11.0.1.

azure-pipelines-pr-snapshot.yml builds every PR into an interactive demo snapshot and posts its URL on the PR. It also attaches an installable npm tarball with a unique 0.0.0-pr.<PR>.<build> version to the ADO build as the npm-package artifact, but never publishes PR packages to npm. Demo deployment uses the BabylonJS-Deployment and BabylonJS-CI-Infrastructure variable groups. Deployment supplies DEPLOY_TOKEN and DEPLOYMENT_SERVER; Infrastructure supplies DEPLOY_ENDPOINT_UPLOAD, SNAPSHOT_CDN_URL, SNAPSHOTS_STORAGE_ACCOUNT, and GITHUB_SERVICE_CONNECTION. Fork PRs still produce the package artifact but skip deployment and commenting so deployment secrets remain unavailable. DEPLOY_TOKEN must remain secret, and the ADO option that makes secrets available to fork builds must remain disabled. The GitHub service connection named by GITHUB_SERVICE_CONNECTION must be pre-authorized for this pipeline before snapshot runs can post PR comments. A manually queued snapshot run must provide its PR number through the prNumber parameter.

Measurement options (env vars)

$env:ANIMS="gradients,path-morph"       # tracked fixture IDs or local anim names
$env:PERF_DURATION="5"                  # seconds per fixture (default 5)
$env:BASELINE_RESULTS="baseline.json"   # optional previous results for report deltas
$env:NO_OPEN="1"                        # don't open the generated report
pnpm measure

What this is, and why

Lottie is a JSON format for vector animations: shapes, gradients, strokes, masks, morphing paths, text, and image layers. The full player parses that document and renders supported content via stencil-then-cover. The binary compiler moves validation, path flattening, tessellation, and packing offline; the binary player samples transforms and morphs from immutable buffers.

Goals

  • WebGL2. The renderer targets the broadly available @babylonjs/lite-gl WebGL2 surface.
  • Explicit source-format entry points. Full accepts JSON; binary accepts only compiler-produced binary animations and has no JSON parser, text renderer, or image renderer.
  • Small bundle, fast time-to-first-frame. Measured continuously (see below).
  • Off-thread in production. The shipped path renders on an OffscreenCanvas inside a Web Worker. Main-thread playback exists in repository tooling for testing and measurement only; it is not a public package mode.

Public API

Every public player runs off-thread on an OffscreenCanvas; the main thread only owns the DOM canvas, sizing, and control messages. The full worker performs JSON parsing and runtime tessellation. The binary worker decodes geometry prepared by the offline compiler. Both workers sample animation and submit GPU work. Local renderer factories remain internal for the workers and repository tooling; they are not package exports.

The architecture has three independent dimensions:

  • Player: full JSON or binary animation.
  • Execution: public playback runs in a worker; main-thread playback is internal demo, benchmark, and test tooling.
  • Delivery: a consumer bundler discovers and emits the selected worker automatically, or the host serves prebuilt worker assets and uses the standalone ESM or classic-script client.

There are two source-format variants:

  • Full JSON renders all runtime-supported layer types, including text and embedded or external images. Use it as the fallback for documents outside the compiler profile.
  • Binary renders the compiler's constrained vector profile from deterministic binary animation assets. Compilation rejects unsupported content instead of silently dropping it.

The player and delivery choices combine as follows. Explicit-URL hosts use one shared standalone client; the supplied worker file selects the player:

| Delivery | Full JSON | Binary | | -------------------------- | ------------------------------------------------------- | -------------------------------------------------------------- | | Bundler (automatic worker) | @babylonjs/lottie-playercreateLottieWorkerPlayer | @babylonjs/lottie-player/binarycreateBinaryWorkerPlayer | | Explicit worker URL (ESM) | /standalone + workers/full.worker.js | /standalone + workers/binary.worker.js | | Classic script | standalone.min.js + workers/full.worker.js | standalone.min.js + workers/binary.worker.js |

Bundler usage

The root entry creates the full worker automatically:

import { createLottieWorkerPlayer, playWorkerAnimationAsync } from "@babylonjs/lottie-player";

const player = createLottieWorkerPlayer();
await playWorkerAnimationAsync(player, {
    container: document.getElementById("animation")!,
    animationSource: "./animation.json",
    loop: true,
    fit: "scale-down",
    onError: () => document.getElementById("fallback")?.removeAttribute("hidden"),
});

The full JSON and binary players support the same aspect-ratio-preserving fit policies:

| fit | Container larger than the animation | Container smaller than the animation | | ------------ | -------------------------------------------------------- | ----------------------------------------------- | | contain | Enlarges until one dimension reaches the container edge. | Shrinks until the entire animation fits. | | scale-down | Keeps the authored dimensions. | Shrinks until the entire animation fits. | | none | Keeps the authored dimensions. | Keeps the authored dimensions and may overflow. |

contain is the default. The player observes container resizes for contain and scale-down; none always uses the Lottie document's top-level w and h, so it does not observe the container. The container's CSS controls canvas alignment and whether overflow is visible or clipped.

Each player handle is one-shot. The first accepted playWorkerAnimationAsync call resolves true after setup is queued; another call on the same handle resolves false, including while a URL is still loading. Use onFirstRender when the first painted frame matters. A worker load, parse, or render failure invokes onError and disposes the player. The callback deliberately carries no error string so production delivery does not pay for diagnostic text; applications should show their normal static fallback and may log the animation URL themselves.

When animationSource is a URL, external image assets (u + p) resolve relative to the final JSON response URL, including after redirects. A parsed document has no source URL, so its external image paths must already be absolute; embedded data: images work in either form.

Compile compatible vector content before shipping the binary player:

npx babylon-lottie-compile animation.json animation.bin
import { createBinaryWorkerPlayer, playWorkerAnimationAsync } from "@babylonjs/lottie-player/binary";

const player = createBinaryWorkerPlayer();
await playWorkerAnimationAsync(player, {
    container: document.getElementById("animation")!,
    animationSource: "./animation.bin",
});

The compiler also exports compileLottieBinary, compileLottieFile, compileLottieProgram, encodeLottieProgram, and getCompiledLottieUnsupportedReasons from @babylonjs/lottie-player/compiler. Use the unsupported-reasons API in asset pipelines that need to route incompatible documents to the full JSON player.

Explicit worker URL

Use /standalone when the host serves a prebuilt worker itself. Pair each constructor with its same-origin worker URL:

import { createLottieWorkerPlayer, playWorkerAnimationAsync } from "@babylonjs/lottie-player/standalone";

const player = createLottieWorkerPlayer({ workerUrl: "/static/workers/full.worker.js" });
await playWorkerAnimationAsync(player, {
    container: document.getElementById("animation")!,
    animationSource: "./animation.json",
});

For a binary animation, call createBinaryWorkerPlayer with workers/binary.worker.js and pass its URL or an ArrayBuffer/Uint8Array source.

Classic-script hosts use the equivalent LiteLottie global, which exposes both constructors. The global name is intentionally stable for existing classic-script hosts.

<script src="./standalone.min.js"></script>
<script>
    const player = LiteLottie.createLottieWorkerPlayer({ workerUrl: "./workers/full.worker.js" });
    LiteLottie.playWorkerAnimationAsync(player, {
        container: document.getElementById("animation"),
        animationSource: "./animation.json",
    });
</script>

Fixed binary splash

For first-paint-critical, fixed-layout binary splashes, the package also ships a paired classic script and binary worker:

  • fixed-binary-splash/client.min.js
  • fixed-binary-splash/worker.min.js

This client auto-starts under a deliberately narrow HTML contract:

<canvas id="l" data-a="animation.bin" style="width: 512px; height: 512px"></canvas>
<script src="./fixed-binary-splash/client.min.js"></script>

Copy the binary animation asset beside the two scripts. The client derives their directory from document.currentScript, loads worker.min.js, and stores the worker on canvas._w for the host's later dismissal path to terminate.

This path is an auto-executing classic script, not an ESM API. It assumes the host has already gated on OffscreenCanvas, provides stable nonzero canvas dimensions, keeps an independent fallback, and owns worker termination. It intentionally omits capability checks, resize observation, callbacks, inline animation objects, variables, configurable looping, and error UI. Use the regular bundler or standalone entries when those capabilities are needed.


Architecture

Rendering pipeline

Per frame, the player walks layers back-to-front, resolves each layer's world matrix (parent chain applied), and dispatches to a renderer keyed by layer kind:

  • Fill (rendering/fill-renderer.ts) — the core. Vector fills via stencil-then-cover: a stencil pass marks pixel coverage (nonzero winding emulated with two cull passes — back faces INCR_WRAP, front faces DECR_WRAP, since lite-gl's stencil is single-sided), then a full-screen cover pass paints the covered region. Also handles solids, linear/radial gradients, strokes (tessellated to geometry in rendering/stroke-geometry.ts), add-mode masks, and opaque vector alpha track mattes. Masks and mattes reserve one stencil bit each, so their intersection needs no texture or extra framebuffer. MSAA comes free from the antialiased default framebuffer.
  • Text (rendering/text-renderer.ts) — rasterizes each text block once on an OffscreenCanvas (so it works on the main thread and in a worker) and draws it as a premultiplied textured quad.
  • Image (rendering/image-renderer.ts) — decodes each asset via loadTexture2D (fetch + createImageBitmap, worker-safe) and draws a textured quad.

Module map (src/)

| Area | Files | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Public entries | index.ts (.), binary.ts (./binary), standalone.ts (./standalone), compiler/compiler.mjs (./compiler) | | JSON model | animation/lottie-raw.ts, animation/parse.ts, animation/sample.ts, animation/matrix.ts, animation/geometry.ts | | JSON player | player/player-core.ts, player/full-player.ts | | Binary player | binary/format.ts, binary/player.ts, client/binary-client.ts, worker/binary.worker.ts | | Rendering | rendering/fill-renderer.ts, rendering/stroke-geometry.ts, rendering/text-renderer.ts, rendering/image-renderer.ts, rendering/layer-renderer.ts, rendering/gl-frame.ts | | Worker delivery | client/runtime.ts, client/blob-worker.ts, client/default-worker.ts, worker/protocol.ts, worker/full.worker.ts |

Worker (src/worker/)

The production off-thread path has one worker per source format:

| File | Role | | ------------------ | ---------------------------------------------------------------------------------------------------------------- | | protocol.ts | Shared lifecycle messages plus distinct inline JSON and binary payloads. | | full.worker.ts | Fetches/parses JSON and drives the full renderer through controller.ts and dispatch.ts. | | binary.worker.ts | Fetches/decodes binary animations, binds immutable geometry, samples transforms and morphs, and drives playback. |

Worker-safety: fill, stroke, mask, and image renderers are DOM-free. Text was the only worker-unsafe renderer (it used document.createElement); it now rasterizes on an OffscreenCanvas and uploads via createDynamicTexture / updateDynamicTexture, so one code path serves both threads.


Performance benchmark

pnpm measure runs the current renderer core against every tracked visual fixture plus optional local animations from anims/. Binary fixtures are compiled during staging and benchmark the resulting binary animation bytes; full fixtures benchmark JSON. ANIMS restricts a run by fixture ID, JSON filename, or local animation name.

Each fixture runs in a fresh page in headed Chrome. The benchmark deliberately drives the internal main-thread renderer so RAF CPU time and WebGL draw calls are directly observable. It reports potential FPS, RAF average and p95, draw calls, initialization time, time to first frame, and JS heap. Production bundle sizes remain guarded separately by tests/worker-client-size.test.ts.

Results are written to measure/.out/results.json and measure/.out/report.html. To compare a change, save the first run's JSON outside .out, then set BASELINE_RESULTS to that file for the second run; the report shows per-metric deltas.

Test fixtures

Local animation JSONs live in the gitignored anims/ directory. Drop any Lottie *.json files you are licensed to test there and the demo + benchmark pick them up. The demo attempts to compile each document and enables the binary player only when compilation succeeds. The benchmark follows each tracked fixture's declared variant.

Visual regression tests

Blocking visual tests use only the hand-authored Apache-2.0 fixtures under tests/visual/fixtures/. They do not read anims/ and do not depend on the Babylon Assets CDN. Normal runs build and exercise the published dist standalone API plus its full/binary workers, then compare their canvases with reviewed goldens:

pnpm build
pnpm test:visual

Goldens are generated locally from the installed Babylon.js Lottie player where it supports the feature, or from the installed lottie-web canvas renderer for masks, mattes, morphs, and images. They are never generated from the candidate renderer. Only regenerate them for an intentional fixture/reference change, and inspect every image before keeping it:

pnpm build
pnpm test:visual:update

The Playwright configuration uses Playwright's pinned full Chromium channel because its ANGLE WebGL2 stencil behavior matches production Chrome; the lightweight headless shell does not render this stencil pipeline reliably. CI installs that pinned Chromium build and uses SwiftShader for a deterministic software-GPU run; local golden review uses the machine's real GPU.


Demo tooling (demo/)

  • serve.mjs — live viewer (pnpm demo, port 5180). Dropdowns for Animation, Renderer (Full JSON / Binary), and Thread (Main / Worker).
  • build.mjs / _shared.mjs — one-shot PR snapshot build and shared esbuild configuration. They bundle the viewer plus the two worker entries.

For a static hosted build, exclude gitignored local animations so they are not copied into the deployment directory:

$env:DEMO_INCLUDE_LOCAL_ANIMS = "false"
pnpm build:demo

Status

Full JSON: fills, solids, linear/radial gradients with animated colors, butt/round-cap strokes with round joins, independent gradient opacity stops, add-mode masks, opaque vector alpha track mattes, text, images, morphing paths, hidden layers, nested group transforms, MSAA, z-order, comp clipping, and parent transforms — in the internal main-thread harness and public worker delivery.

Binary: shape and null layers, layer transforms and parenting, animated nested group transforms, fixed-topology GPU morphs, solid and static gradient fills, static compound nonzero fills with holes, add masks, opaque alpha mattes, and the compiler's constrained static stroke profile. The compiler reports and rejects unsupported content; it is not a generic replacement for every shape-only Lottie document.

Not yet supported by full JSON: mask subtract/intersect/inverted/feather, inverted/luma/fractional-alpha track mattes, square stroke caps, non-round stroke joins, even-odd fill rules, time stretch, precompositions, mergePaths, trimPath, per-glyph text animators, and gradient strokes.

The source manifest remains private to prevent accidental publication from the repository root. The release pipeline builds and publishes the generated dist/ package, including root, ./binary, ./compiler, ./standalone, the classic standalone client, the fixed binary splash pair, and both prebuilt workers.