loadersz-core README

The project's README from github.com/lumberjacque/loadersz-core. As one markdown file: README.md.

loadersz

npm version npm downloads CI bundle size single loader size motion states license TypeScript core dependencies

Framework-agnostic, dependency-free Canvas loaders for the browser. loadersz ships as a native Web Component and a small imperative TypeScript API-no React, SVG filters, or runtime dependencies.

150 motion states. One fixed state is 2.5–3.1 kB gzipped; the complete switchable library is available from one import.

Install

npm install loadersz

Enumerate available states

Use the tiny, side-effect-free states entry when building a picker or documentation UI:

import { LOADER_STATES } from "loadersz/states";

console.log(LOADER_STATES); // ["working", "searching", …]

Use the category metadata when building a picker or gallery. It keeps product-style loaders, loaders, systems, data & telemetry, reasoning, atmosphere and motion studies in the same order as the official website:

import { LOADER_CATEGORIES } from "loadersz/states";

for (const category of LOADER_CATEGORIES) {
  console.log(category.label, category.states);
}

Import once in your application to register the custom element safely:

import "loadersz";

Custom element

<loadersz-loader
  state="calibrating"
  size="144"
  speed="1.15"
  density="1"
  theme="dark"
  aria-label="Calibrating"
></loadersz-loader>

size is required in practice: it is the square canvas side in CSS pixels. Use 64 for a compact status indicator, 144 for a card, or 280 for a hero-sized loader.

Attributes

Attribute Type Default Description
state state name working Selects the visual geometry.
size number 96 Square side in CSS pixels; values below 16 are clamped.
speed number 1 Timeline multiplier.
density number 1 Geometry detail; clamped to 0.35–2.
particle-radius number 1 Multiplies visible particle thickness; clamped to 0.5–2.5.
theme auto, dark, light auto Canvas colour scheme.
hue 0–360 unset Overrides a mode's native colour palette.
color CSS colour string unset Overrides hue; accepts hex, CSS colours, and var(--token).
paused boolean attribute unset Stops frame scheduling and keeps the current frame visible.
force-motion boolean attribute unset Overrides a reduced-motion preference; use only when appropriate.
aria-label string Loading Accessible label applied to the internal canvas.

Colour modes

Omit both hue and color to preserve the loader's native treatment. That can be a multi-colour palette or deliberately monochrome grey, depending on the movement. Set hue to recolour every visible particle with one hue, or set color for one exact CSS colour. color takes precedence over hue.

States

working, searching, connecting, weaving, shaping, listening, breathing, composing, solving, observing, dreaming, charging, flowing, awakening, coding, transcending, singing, growing, blooming, wandering, decoding, calibrating, attracting, shattering, crystallizing, constellating, folding, echoing, balancing, weathering, mapping, forging, orbiting, racing, bubbling, spinning, electrifying, flocking, throbbing, cascading, spiraling, juggling, eclipsing, resonating, condensing, dispersing, prisming, levitating, synchronizing, unraveling, pondering, deducing, branching, focusing, reflecting, weighing, recalling, tracing, converging, questioning, glimmering, radiating, harmonizing, twinkling, flickering, shimmering, surfacing, vibrating, illuminating, sparkling, loading, buffering, typing, processing, synthesizing, considering, uploading, queuing, associating, evaluating, reasoning, exploring, linking, resolving, and imagining.

Framework adapters

The core package remains a native Web Component. Typed adapters are available for the three frameworks that need framework-specific TypeScript or component integration.

React

import { LoaderszLoader } from "loadersz/react";

export function Status() {
  return (
    <LoaderszLoader
      state="racing"
      size={144}
      speed={1.2}
      ariaLabel="Loading results"
    />
  );
}

Importing loadersz/react also adds type support for direct custom-element JSX:

import "loadersz/react";

const loader = <loadersz-loader state="orbiting" size={96} />;

Vue 3

<script setup lang="ts">
import { LoaderszLoader } from "loadersz/vue";
</script>

<template>
  <LoaderszLoader
    state="bubbling"
    :size="144"
    :speed="1.1"
    aria-label="Loading"
  />
</template>

Svelte 4 and 5

<script lang="ts">
  import 'loadersz/svelte';
</script>

<loadersz-loader state="spiraling" size={144} aria-label="Loading" />

Angular

Use the standalone Angular directive. It makes the native element known to Angular and adds typed bindings without CUSTOM_ELEMENTS_SCHEMA. The runtime import is intentionally explicit, so the same pattern works with a small direct state import. Keep the loader in normal HTML — never inside an <svg> or <defs> block.

import { Component } from "@angular/core";
import "loadersz";
import { LoaderszLoader } from "loadersz/angular";

@Component({
  standalone: true,
  selector: "app-root",
  imports: [LoaderszLoader],
  template: `
    <loadersz-loader
      [state]="state"
      [size]="144"
      aria-label="Loading"
    ></loadersz-loader>
  `,
})
export class App {
  readonly state = "racing" as const;
}

For Solid, Qwik, Lit, and plain HTML, import loadersz and use <loadersz-loader> directly.

Which import should I use?

Framework Loader can change at runtime One fixed loader
React import { LoaderszLoader } from 'loadersz/react' import 'loadersz/racing' plus React's type-only import below
Vue 3 import { LoaderszLoader } from 'loadersz/vue' import 'loadersz/racing' and use the native element
Svelte import 'loadersz/svelte' import 'loadersz/racing' plus import type {} from 'loadersz/svelte'
Angular import 'loadersz' + LoaderszLoader import 'loadersz/racing' + LoaderszLoader
Lit, Solid, Qwik, HTML import 'loadersz' import 'loadersz/racing'

The controls are always the same. The native element spells its multi-word attributes as aria-label, force-motion, and particle-radius; React and Vue wrappers spell them as ariaLabel, forceMotion, and particleRadius. state, size, speed, density, hue, color, theme, and paused keep the same name.

Single-mode imports

When a loader will never change state, use its direct entry point. It includes the Canvas core and exactly one geometry builder-no tree-shaking configuration required.

import "loadersz/racing";
<loadersz-loader
  state="racing"
  size="144"
  speed="1.15"
  aria-label="Loading results"
></loadersz-loader>

The direct entry's visual state is fixed by its import. The state attribute is accepted so markup stays familiar, but cannot load the other 84 animations. Every state name has a matching entry point: loadersz/working, loadersz/solving, loadersz/racing, and so on.

In React, a direct entry can stay small too. Import the fixed runtime entry and the adapter types only; TypeScript removes the type-only import from the browser bundle.

import "loadersz/racing";
import type { LoaderszReactProps } from "loadersz/react";

const loaderProps = { state: "racing", size: 96 } satisfies LoaderszReactProps;

export function Loading() {
  return <loadersz-loader {...loaderProps} aria-label="Loading" />;
}

The direct import itself is framework-agnostic: it always registers the same native element and supports the same state, size, speed, density, hue, color, theme, paused, and force-motion attributes. Framework wrapper types are intentionally specific to their framework: use LoaderszReactProps for React, loadersz/vue for the typed Vue component, and import type {} from 'loadersz/svelte' alongside a direct entry for Svelte template typing. The Vue wrapper imports the complete switchable component, so use the native element when the smallest single-state bundle matters.

For a fixed canvas you own yourself, the same entry point exposes a fixed imperative controller:

import { LoaderszLoader } from "loadersz/racing";

const canvas = document.querySelector<HTMLCanvasElement>("#loading");
if (!canvas) throw new Error("Missing canvas");

const loader = new LoaderszLoader(canvas, {
  size: 144,
  speed: 1.15,
  ariaLabel: "Loading results",
});

Use the root import when a component must change between states at runtime:

import "loadersz";

loadersz/modes remains available for applications that want named fixed-mode factories and already rely on an ESM-aware production bundler:

import { racing } from "loadersz/modes";

const canvas = document.querySelector<HTMLCanvasElement>("#loading");
if (!canvas) throw new Error("Missing canvas");

const loader = racing(canvas, {
  size: 144,
  speed: 1.15,
  ariaLabel: "Loading results",
});

The returned controller still supports setOptions, paused, colour, speed, density, and destroy(). Its visual mode is fixed to the imported factory.

Imperative API

Use the imperative API when your application owns a canvas or controls the lifecycle directly.

import { LoaderszLoader } from "loadersz";

const canvas = document.querySelector<HTMLCanvasElement>("#loader");
if (!canvas) throw new Error("Missing canvas");

const loader = new LoaderszLoader(canvas, {
  state: "solving",
  size: 160,
  speed: 1.1,
  theme: "dark",
  ariaLabel: "Solving",
});

loader.setOptions({ state: "forging", size: 200, hue: 28 });
loader.destroy();

All exported types and methods include TSDoc, so editors show parameter descriptions, defaults, return values, and lifecycle behaviour on hover.

Accessibility and performance

Development

Install dependencies and enable the local Git hooks once:

npm install
npm run hooks:install

Commits follow Conventional Commits. Pre-commit checks format and lint staged files. The release package intentionally contains no install lifecycle scripts.

Browser benchmark UI

Start the interactive production-build benchmark:

npm run benchmark:ui

Open http://127.0.0.1:4174, choose a scenario, and select Run benchmark. Stop the local server with Ctrl+C. See BENCHMARKING.md for A/B comparisons, equivalence checks, CI behaviour, and measurement rules.

License

MIT © 2026 lumberjacque.

loadersz-core (lumberjacque/loadersz-core)

Searching Database…

这是什么?loadersz 是一个零依赖的浏览器 Canvas 加载动画库,以原生 Web Component 的形式发布,配有精简的命令式 TypeScript API 和 150 种可切换的动效状态。
这是个 Web Component,还是绑定某个框架的库?核心是一个纯原生 Web Component,带 TypeScript 命令式 API——不需要 React、SVG 滤镜或任何运行时依赖。在此之上为 React、Vue 3、Svelte 和 Angular 提供了带类型的包装适配器。
怎么把加载动画加进我的项目?先导入一次包以注册自定义元素,然后直接写进标记即可;只需要一种状态的应用可以改为导入固定入口(如 'loadersz/racing'),打包体积更小。
使用它需要装 React 或 Vue 吗?不需要——核心零常规运行时依赖。只有当你导入 React、Vue、Svelte 的带类型适配器入口时,才需要它们作为可选 peer 依赖。
单一状态导入之后还能切换到别的动画吗?不能——loadersz/racing 这样的直接入口只打包自己的几何构建器,虽然为了标记写法一致仍然接受 state 属性,但它无法加载其余 84 种动画中的任何一种。
包含多少种加载动画?共有 150 种动效状态,分为产品风格加载器、系统、数据与遥测、推理、氛围、动效研究等类别,顺序与官网一致。
它遵循「减弱动态效果」设置吗?遵循,它默认尊重 prefers-reduced-motion,并在隐藏的标签页中暂停动画;需要时可以用 force-motion 属性覆盖。
我能给加载动画换色吗?可以——设置 hue 属性(0-360)用单一色调给原生调色板着色,或者设置 color 指定精确的 CSS 颜色,color 的优先级高于 hue。
单个加载动画的包有多大?一个固定状态 gzip 后约 2.5-3.1 kB,因为它只包含 Canvas 核心加一个几何构建器,不需要任何 tree-shaking 配置。
Size
0.7 MB
Stars
163
Age
1mo
Commits · 90 Days