Vanilla Disintegratev1.6.1
EN
On this page

Snapshot-based effects receive pixels through a replaceable SnapshotCapture adapter. The core library does not depend on a particular DOM-to-Canvas engine: the root entry accepts a custom adapter, while /snapdom supplies one ready to use.

SnapshotCapture

type SnapshotCapture = (
  element: HTMLElement,
  context: SnapshotCaptureContext,
) => HTMLCanvasElement | Promise<HTMLCanvasElement>;

interface SnapshotCaptureContext {
  operation: 'remove' | 'restore' | 'prepare';
  signal: AbortSignal;
  invalidate?: boolean;
  restoreRootOpacity?: string;
}

The adapter must return a canvas containing the current visual representation of element. Its pixel dimensions determine source resolution; the library independently measures the element’s CSS bounds and places the animation overlay over them.

Context fieldMeaning
operationprepare for background capture, otherwise the active remove or restore operation
signalAborts when preparation, the operation, or the owning instance is cancelled
invalidateRequests a fresh engine capture after explicit preparation or cache invalidation
restoreRootOpacityOriginal computed opacity of the root before restore() temporarily conceals the live element

Check signal.aborted before expensive work and stop promptly when the underlying engine supports cancellation. During restoration, apply restoreRootOpacity to the captured root instead of capturing the temporary concealed state.

import Disintegrator, { type SnapshotCapture } from 'vanilla-disintegrate';

const capture: SnapshotCapture = async (element, context) => {
  if (context.signal.aborted) {
    throw new DOMException('Capture aborted.', 'AbortError');
  }

  return captureWithMyEngine(element, {
    signal: context.signal,
    invalidate: context.invalidate,
    rootOpacity: context.restoreRootOpacity,
  });
};

const effects = new Disintegrator({
  preset: 'dust',
  capture,
});

Set needsSnapshot: false on a custom effect phase that animates DOM, SVG, CSS, WAAPI, or another renderer without source pixels. If both phases are snapshotless, the /core entry avoids capture and particle dependencies entirely.

createSnapdomCapture(options?)

The adapter uses SnapDOM ^3.1.0 and its SVG renderer. SnapdomCaptureOptions accepts native SnapdomOptions except canvas and engine: each capture returns an independently owned canvas that the effect can release safely.

Explicit width or height takes precedence over scale; dpr multiplies the output resolution. For example, { width: 200, scale: 2, dpr: 2 } requests a 400-pixel-wide canvas before the pixel budget applies.

maxCapturePixels defaults to 8,000,000. The adapter reduces DPR before rasterization to fit that budget; false disables it. The budget covers the output bitmap, not DOM traversal or resource embedding. Particle renderQuality is applied separately after capture.

import Disintegrator, { createSnapdomCapture } from 'vanilla-disintegrate/snapdom';

const capture = createSnapdomCapture({
  dpr: 2,
  exclude: '[data-capture-ignore]',
});

const effects = new Disintegrator({ preset: 'dust', capture });

The adapter enables reconcile: true to preserve element sizes and text wrapping in snapshots. This adds a layout measurement pass; set reconcile: false to skip it. Other policies follow SnapDOM defaults, including embedFonts: 'auto', invalidate: false, and filterMode: 'hide'. Automatic DPR is limited to 2; an explicit dpr overrides that limit. Eligible unchanged captures use SnapDOM’s automatic memoization.

Images use SnapDOM’s resource handling. Set placeholders: false to keep an empty slot for a failed image, or provide fallbackURL. A custom filter is passed through unchanged. Pending resources may delay capture; prepare custom lazy images before starting an effect.

By default the exported image matches the root box, including its rotation and scale, without extra shadow or blur padding. Explicit clip, enabled outerShadows, or outerTransforms: false selects SnapDOM’s requested capture geometry. Safari receives a density correction to keep embedded fonts and SVG sharp. Restore captures preserve the root’s original opacity while the live element remains concealed.

After CSSOM changes such as sheet.insertRule() or CSSStyleRule.style, call effects.invalidate(element). This discards prepared snapshots and requests a fresh SnapDOM style capture, even with snapdom.invalidate: false. Explicit prepare() also requests a refresh; clearPrepared() requests one on subsequent captures. With a standalone capture function, pass context.invalidate: true for that call or configure invalidate: true to refresh on every call.

Prepared canvases have a separate lifecycle. Their mutation observation is disabled by default: call effects.invalidate() after visual changes, or enable preparation.observeMutations for DOM changes. CSSOM edits still require explicit invalidation. Plugins follow the SnapDOM plugin contract.

SnapDOM cannot cancel an in-flight capture. The adapter rejects an already-aborted call; the library disposes results that arrive after an operation is cancelled.

The /snapdom constructor

import Disintegrator from 'vanilla-disintegrate/snapdom';

type SnapdomDisintegratorOptions = DisintegratorOptions & {
  snapdom?: SnapdomCaptureOptions;
};

const effects = new Disintegrator({
  preset: 'vapor',
  snapdom: { dpr: 1.5 },
});

snapdom forwards options to the automatically created adapter. Supplying capture replaces that adapter completely; in that case snapdom has no effect.

The root vanilla-disintegrate entry does not import SnapDOM and requires capture only when the selected effect phase needs a snapshot.

Capture resolution and render quality

Capture and rendering are separate stages:

  1. The capture adapter creates the source canvas and chooses its pixel density.
  2. The particle renderer applies renderQuality when turning that source into WebGL textures and an expanded animation surface.

Increasing renderQuality cannot recover detail absent from the captured canvas. Increasing capture DPR creates more source pixels and therefore raises capture time, memory use, texture upload cost, and potentially particle preparation cost.

No DOM-to-Canvas engine is guaranteed to reproduce every browser-rendered pixel. See the limitations section for known differences involving text rasterization, browser zoom, filters, embedded content, and cross-origin resources.

Edit this page on GitHub