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

react-particle-morpheus

v1.0.3

Published

React component to shatter, vaporize, or dissolve children elements into particles.

Readme

react-particle-morpheus

⚠️ This documentation was generated by AI. A proper hand-written version will be coming in the future. For now, it should serve as a solid starting point.

A React component library for shattering, vaporizing, and dissolving any children element into particles. Supports multiple animation strategies, mask generators, and physics effects — all rendered on a single global <canvas> with full control via ref.

Installation

npm install react-particle-morpheus

Peer dependencies: react >= 18, react-dom >= 18


Quick Start

import { ParticlesProvider, Vaporize, type VaporizeRef } from "react-particle-morpheus";
import { useRef } from "react";

function App() {
  const vaporizeRef = useRef<VaporizeRef>(null);

  return (
    <ParticlesProvider fps={120}>
      <Vaporize
        ref={vaporizeRef}
        timeMaskGenerator="topLeftDiagonal"
        particleInitialState="explosion"
        particleEffect="gravitationBottom"
        config={{ maxParticles: 2000 }}
        onEnd={() => console.log("Animation finished")}
      >
        <div style={{ padding: 40, background: "#fff", borderRadius: 16 }}>
          <h1>Click the button to dissolve me!</h1>
        </div>
      </Vaporize>

      <button onClick={() => vaporizeRef.current?.start()}>
        Start
      </button>
    </ParticlesProvider>
  );
}

Initialization — <ParticlesProvider>

ParticlesProvider is a required context provider that manages the global <canvas> and the requestAnimationFrame animation loop. It must wrap all <Vaporize> / <VaporizeDev> components.

import { ParticlesProvider } from "react-particle-morpheus";

<ParticlesProvider fps={120}>
  {/* Any Vaporize components go here */}
</ParticlesProvider>

Props

| Prop | Type | Required | Description | |------|------|----------|-------------| | fps | number | ✅ | Target frames per second for the animation loop. Typical values: 60 or 120. | | children | React.ReactNode | ✅ | Any React children — including multiple <Vaporize> instances. |

What does the Provider do?

  • Mounts a single <canvas> with position: fixed, z-index: 9999, and pointer-events: none — covering the entire viewport.
  • Runs a single RAF (requestAnimationFrame) loop that iterates over all registered particle groups.
  • Automatically removes a group when all of its particles have died.
  • Handles window resize (debounced at 100 ms).

useParticles() Hook

Used internally by <Vaporize>. Provides access to methods: addGroup, removeGroup, startGroup, stopGroup, detachGroup, updateGroupSource, and the current fps. Throws an error if used outside of <ParticlesProvider>.


<Vaporize> Component

The main component of the library. Wraps any React element, takes a snapshot of it (via html-to-image), generates particles in a Web Worker, and registers the group with the Provider. The entire animation is controlled via ref.

import { Vaporize, type VaporizeRef } from "react-particle-morpheus";

const ref = useRef<VaporizeRef>(null);

<Vaporize
  ref={ref}
  timeMaskGenerator="centerOut"
  particleInitialState="explosion"
  particleEffect="gravitationBottom"
  config={{ maxParticles: 3000, showLogs: true }}
  onStart={() => console.log("Start!")}
  onShatterFinished={() => console.log("Element fully shattered")}
  onEnd={() => console.log("All particles dead")}
  onReset={() => console.log("Reset")}
>
  <MyComponent />
</Vaporize>

Props

| Prop | Type | Required | Default | Description | |------|------|----------|---------|-------------| | children | React.ReactNode | ✅ | — | The element to vaporize. | | ref | React.Ref<VaporizeRef> | ❌ | — | Ref providing access to control methods. | | timeMaskGenerator | keyof MasksGenerators | ✅ | — | Shatter strategy (order in which pixels detach as particles). | | particleInitialState | keyof ParticleInitialStates | ✅ | — | Initial particle state (velocity, direction). | | particleEffect | keyof ParticleEffects | ✅ | — | Physics effect applied every frame. | | config | Partial<VaporizeConfig> | ❌ | see below | Configuration object. | | onStart | () => void | ❌ | noop | Called when the animation starts. | | onShatterFinished | () => void | ❌ | noop | Called when the element is fully shattered into particles (all particles have spawned). | | onEnd | () => void | ❌ | noop | Called when all particles have died. | | onReset | () => void | ❌ | noop | Called after a reset. |

VaporizeConfig

| Field | Type | Default | Description | |-------|------|---------|-------------| | maxParticles | number | 1000 | Maximum number of particles. More = more detailed effect, but higher CPU cost. | | fps | number | 60 | Target FPS (independent of the Provider — controls internal setup throttling). | | autoInitialize | boolean | true | Whether to automatically run snapshot + particle generation. If false, you must call resetAll() manually. | | showLogs | boolean | false | Enables [Vaporize] console logs — useful for debugging. |

Ref Methods — VaporizeRef

| Method | Description | |--------|-------------| | start() | Starts the animation (requires isReady === true and isRunning === false). | | stop() | Pauses the animation — particles keep their position, elapsed time is preserved. | | reset() | Resets particles to their initial position (without re-snapshotting). | | resetAll() | Full reset — new snapshot, worker, mask generation. | | refreshSnapshot() | Refreshes the children snapshot without resetting particles (e.g. after content changes). | | saveSnapshot(fileName?) | Downloads the current snapshot as a PNG file. | | isReady() | Returns true if snapshot + particles + masks are ready. | | isRunning() | Returns true if the animation is currently running. |


<VaporizeDev> Component

A development version of <Vaporize> with a built-in DevTools panel — a floating UI for changing parameters in real time. Props are the same as <Vaporize>, but all strategies have default values, so nothing is required (except children).

import { VaporizeDev } from "react-particle-morpheus";

<VaporizeDev
  config={{ maxParticles: 5000 }}
  onShatterFinished={() => setIsVisible(false)}
  onReset={() => setIsVisible(true)}
>
  <MyComponent />
</VaporizeDev>

Differences from <Vaporize>

| | Vaporize | VaporizeDev | |---|---|---| | DevTools UI | ❌ | ✅ Floating panel with gear icon | | timeMaskGenerator | required | defaults to "topLeftDiagonal" | | particleInitialState | required | defaults to "explosion" | | particleEffect | required | defaults to "gravitationBottom" | | Runtime parameter changes | ❌ | ✅ Via DevTools panel | | Production use | ✅ | ❌ Development only |

DevTools Panel

The DevTools panel renders as a floating button (⚙️) next to the component. It can be dragged around. Clicking it expands into a panel with:

  • Buttons: Start, Stop, Reset, ResetAll, Refresh Snapshot, Save Snapshot
  • Selects: Mask Generator, Initial State, Particle Effect
  • Config: maxParticles, FPS, autoInitialize, showLogs

Changing the Mask Generator, Initial State, or maxParticles triggers a full remount of the <Vaporize> component (via key change).


Available Strategies

Mask Generators (timeMaskGenerator)

Control the order in which pixels detach from the element as particles.

| Key | Description | |-----|-------------| | leftToRight | Left to right | | rightToLeft | Right to left | | topToBottom | Top to bottom | | bottomToTop | Bottom to top | | topLeftDiagonal | Diagonal from top-left corner | | topRightDiagonal | Diagonal from top-right corner | | bottomLeftDiagonal | Diagonal from bottom-left corner | | bottomRightDiagonal | Diagonal from bottom-right corner | | sand | Sand-falling effect — waves from bottom, alternating left/right | | centerOut | Radially from center outward | | edgesIn | From edges toward center | | splitHorizontal | Expanding from center horizontally | | splitVertical | Expanding from center vertically | | random | Random order |

Particle Initial States (particleInitialState)

Define the initial velocity and direction of each particle at spawn time.

| Key | Description | |-----|-------------| | explosion | Random direction, random force — classic explosion | | scatter | Scatters mostly upward and to the sides | | freefall | No initial velocity — particles start falling immediately | | fountain | Fountain — strong upward throw | | implosion | Reversed explosion — particles fly toward center | | vortex | Rotational (tangential) motion | | raindrop | Falling like raindrops | | drift | Gentle, slow drift in a random direction |

Particle Effects (particleEffect)

Physics function called every frame for each living particle.

| Key | Description | |-----|-------------| | blowDown | Constant downward velocity | | blowUp | Constant upward velocity | | gravitationBottom | Gravitational acceleration downward | | gravitationUp | Gravitational acceleration upward | | wavyFloating | Sinusoidal wave motion + gentle floating | | flickerFade | Random opacity flickering | | windyGravity | Wind to the right + gravity downward | | swirl | Swirling (velocity vector rotation) | | shrinkFade | Rapid opacity fadeout |


When It Does NOT Work / Known Limitations

  • Custom-styled scrollbars — if the children element has custom scrollbars (CSS ::-webkit-scrollbar) and does not use a scrollbar library (e.g. simplebar, react-custom-scrollbars), the snapshot may not capture them correctly or the effect may look unnatural.
  • Moving elements — the effect does not work correctly when the children element is mid-animation (CSS/JS), moving, or resizing at the time of snapshotting. The snapshot is taken at a single point in time and assumes a static element position.
  • Elements with position: fixed/sticky inside children — the html-to-image snapshot may incorrectly render the position of such elements.
  • Cross-origin resources — images or fonts from another domain (without CORS) will not be included in the snapshot.
  • Very large elements — for elements with a large pixel area (e.g. 2000×2000+), generating masks and particles in the worker may take a noticeable amount of time. Adjust maxParticles accordingly.
  • SSR / Server Components — the library requires window, canvas, and Web Worker — it works exclusively on the client side.
  • Multiple <ParticlesProvider> instances — there should be one Provider in the tree. Nesting multiple Providers will create multiple canvases.

Architecture (in brief)

  1. <ParticlesProvider> mounts a global <canvas> and runs a single RAF loop.
  2. <Vaporize> on mount:
    • Takes a snapshot of children (html-to-imagetoCanvas)
    • Sends data to a Web Worker that generates particles + CSS masks
    • Registers the group with the Provider (addGroup)
  3. start() → Provider sets isRunning=true, the RAF loop updates physics and draws particles.
  4. Every frame, the Provider calls onFrame — Vaporize synchronizes the children's CSS mask (the element gradually disappears).
  5. When all particles have spawned → onShatter. When all particles die → onEnd + group auto-removal.

API Exports

// Components
export { Vaporize } from "./Vaporize";
export { VaporizeDev } from "./VaporizeDev";
export { ParticlesProvider, useParticles } from "./PariclesProvider";

// Strategies (for advanced use / creating your own)
export { MasksGenerators } from "./maskGenerators";
export { ParticleEffects } from "./particleEffects";
export { ParticleInitialStates } from "./particleInitialStates";

// Types
export type { VaporizeRef } from "./Vaporize";
export type { VaporizeConfig, Particle, ParticleEffect, ParticleInitialState, TimeMaskGenerator } from "./types";

License

MIT