Vanilla Disintegrate recreates the recognizable Thanos-snap effect when removing and restoring any measurable DOM element.
Installation
Use any supported package manager:
# npm
npm install vanilla-disintegrate @zumer/snapdom
# Yarn
yarn add vanilla-disintegrate @zumer/snapdom
# pnpm
pnpm add vanilla-disintegrate @zumer/snapdom
# Bun
bun add vanilla-disintegrate @zumer/snapdom
The library captures the current appearance of an element before splitting it into particles, and the capture library is your choice. The package ships five tree-shakable entry points:
| Entry | Contents | Requires |
|---|---|---|
vanilla-disintegrate/core | Lifecycle, layout and audio for custom effects, without particles or bundled presets. | Nothing |
vanilla-disintegrate/particles | Particle factories and reusable geometry configurations. | Nothing |
vanilla-disintegrate/sounds | URLs of the four bundled audio files, without the runtime. | Nothing |
vanilla-disintegrate | Disintegrator with all four complete visual-and-audio presets. You supply capture. | Nothing |
vanilla-disintegrate/snapdom | The same complete presets with SnapDOM as default capture. | @zumer/snapdom |
The default and /snapdom entries export the identical Disintegrator API. Every instance must receive exactly one complete preset or one custom effect; there is no implicit default. Use /core for custom snapshotless effects without bundling WebGL or built-in audio.
/core exports Disintegrator, defineEffect, definePreset, and the public types. /particles exports createParticleEffect, particlePresets, both particle animation factories, and their option types; it does not create an instance. This lets an advanced build compose only the layers it needs. The following example uses a built-in geometry as a silent custom effect; captureElement stands for the adapter described later on this page:
import Disintegrator from 'vanilla-disintegrate/core';
import { createParticleEffect, particlePresets } from 'vanilla-disintegrate/particles';
const effects = new Disintegrator({
capture: captureElement,
effect: createParticleEffect({ remove: particlePresets.dust }),
});
For the shortest setup, import /snapdom and choose one complete preset:
import Disintegrator from 'vanilla-disintegrate/snapdom';
const effects = new Disintegrator({ preset: 'dust' });
const card = document.querySelector<HTMLElement>('.card');
if (card) {
effects.remove(card);
}
remove() returns immediately. Use operation.finished only when later code must wait for the visual to settle.
Remove and restore the same node
Set retain: true only when the original node may be needed again. The application still decides where to insert it.
const removal = effects.remove(card, {
retain: true,
});
await removal.finished;
if (removal.removalId) {
const retained = effects.take(removal.removalId);
if (retained) {
list.append(retained);
await effects.restore(retained).finished;
}
}
The restore phase uses the complete preset remembered during removal unless the call supplies another preset or a custom effect.
Use another capture library
capture is a function: it takes an element and returns a <canvas>, or a promise for one. Any library that does that fits, such as html2canvas:
import html2canvas from 'html2canvas';
import Disintegrator from 'vanilla-disintegrate';
const effects = new Disintegrator({
preset: 'dust',
capture: (element, context) => {
if (context.signal.aborted) throw new DOMException('Capture aborted.', 'AbortError');
return html2canvas(element, {
backgroundColor: null,
logging: false,
scale: 1,
useCORS: true,
onclone: (_document, clone) => {
if (context.restoreRootOpacity !== undefined) {
clone.style.setProperty('opacity', context.restoreRootOpacity, 'important');
}
},
});
},
});
The supplied function completely replaces capture. Import the default vanilla-disintegrate entry on this path: it has no runtime dependencies. @zumer/snapdom is an optional peer dependency used only by /snapdom, so SnapDOM does not enter the module graph here.
The Capture API documents the adapter context, cancellation contract, and createSnapdomCapture() defaults.
Local setup or CDN
To integrate Vanilla Disintegrate quickly without a bundler or package manager, load it from the CDN or download the archive containing the latest version for local use.
The IIFE build includes SnapDOM and exposes VanillaDisintegrate globally:
<script src="https://cdn.jsdelivr.net/npm/vanilla-disintegrate@latest/dist/vanilla-disintegrate.iife.min.js"></script>
<script>
const effects = new VanillaDisintegrate.Disintegrator({ preset: 'dust' });
effects.remove(document.querySelector('.card'));
</script>
The archive contains a minimal index.html, the IIFE build, licenses, and all built-in sounds. Serve the extracted directory through a local HTTP server so the browser can load its audio. When copying the IIFE manually, keep the sounds directory next to the script; the CDN version resolves the matching assets automatically.
Clean up
Call destroy() when the owning view or application is permanently disposed. It cancels active visuals, clears prepared snapshots, stops observers, and releases all retained references.
effects.destroy();