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

lazy-vfx

v1.1.6

Published

Effortless high-end visual effects for React and Three.js

Downloads

709

Readme

☄️ Lazy VFX

Effortless high-end visual effects for the modern web, built for React & Three.js

Lazy VFX is a minimal, shader-driven VFX engine designed for modern web apps using React and Three.js. It abstracts away all the math and plumbing for emitters, GPU-accelerated particles, and real-time shaders, so you can stay focused on building cinematic, interactive experiences.

Live demo - Fireworks demo - Wizard Game demo


✨ Features

  • Modular Emitters — Create and control particle sources with flexible settings using <VFXEmitter>.
  • Custom GLSL Shaders — GPU-accelerated with built-in vertex & fragment shaders, easily extensible for custom magic.
  • Centralized State — Driven by a single VFXStore for consistent, live-reloadable scene effects and controls.
  • Fast Tooling — Zero-config Vite setup, instant HMR, rapid production deployments.
  • Leva Controls — Out-of-the-box UI for tuning and exporting effects.

🚀 Quick Install

Use your favorite package manager:

# With pnpm
pnpm add lazy-vfx

# Or npm
npm install lazy-vfx

# Or yarn
yarn add lazy-vfx

🛠️ Usage Example

Lazy VFX uses a two-component system:

  • VFXParticles: Defines the particle system and its rendering properties
  • VFXEmitter: Controls how and when particles are emitted into the scene

Add cinematic particles in seconds to any React Three Fiber scene:

import { VFXParticals, VFXEmitter } from 'lazy-vfx';
import {
  Environment,
  OrbitControls,
  Stats,
  useTexture,
} from "@react-three/drei";


// Also import your alphaMap or use a texture

function Experience() {
    const text = useTexture(
    "https://static.thenounproject.com/png/4312916-200.png",
  );

  return (
    <>
      <Stats />
      <OrbitControls enablePan={false} />
      <Environment preset="sunset" />

      {/* Step 1: Define your particle system */}
      <VFXParticles
        name="sparks" // A unique identifier for this particle system
        settings={{
          nbParticles: 10000, // Maximum number of particles to allocate
          intensity: 2, // Brightness multiplier
          renderMode: "billboard", // "billboard" or "mesh" or "stretchBillboard"
          fadeAlpha: [0.5, 0.5], // Opacity fade in/out settings
          fadeSize: [0, 0], // Size fade in/out settings
          gravity: [0, -20, 0], // Apply gravity (x, y, z)
        }}
        alphaMap={text}
        // geometry={<sphereGeometry />}
      />

      {/* Step 2: Define your emitter */}
      <VFXEmitter
        debug // Show debug visualization
        emitter="sparks" // Target the particle system by name
        settings={{
          duration: 4,  // Emission cycle duration in seconds
          delay: 0, // Time delay before starting emission
          nbParticles: 10000, // Number of particles to emit per cycle
          spawnMode: "time", // Emission mode: 'time' or 'burst'
          loop: true, // Continuously emit particles (only if `spawnMode` is 'time')

           // Position range (min/max)
          startPositionMin: [0, 0, 0],
          startPositionMax: [0, 0, 0],

          // Rotation range (min/max)
          startRotationMin: [0, 0, 0],
          startRotationMax: [0, 0, 0],
           // Rotation speed range (min/max)
          rotationSpeedMin: [0, 0, 0],
          rotationSpeedMax: [0, 0, 0],

           // Particle lifetime range [min, max]
          particlesLifetime: [0.1, 5],

          // Particle speed range [min, max]
          speed: [1, 10],

          // Direction range (min/max)
          directionMin: [-0.5, 0, -0.5],
          directionMax: [0.5, 1, 0.5],
 
          // Color at start - an array of strings for random selection
          colorStart: ["#ffe500", "#ffe500"],

           // Color at end - an array of strings for random selection
          colorEnd: ["#ffe500", "#ffffff"],

          // Particle size range [min, max]
          size: [0.1, 0.5],
        }}
      />
    </>
  );
}

Custom Geometry Example

You can use custom geometries for your particles:

import { useGLTF } from '@react-three/drei';

const CustomParticles = () => {
  // Load the GLTF model. Make sure the path to your .glb file is correct.
  const { nodes } = useGLTF('/models/sword.glb');

  return (
    <>
      <VFXParticles
        name="swords"
        geometry={nodes?.Sword?.geometry ? <primitive object={nodes.Sword.geometry} /> : null}
        settings={{
          nbParticles: 1000,
          renderMode: "mesh",
          intensity: 2,
        }}
      />

      <VFXEmitter
        emitter="swords"
        settings={{
          spawnMode: "burst",
          nbParticles: 100,
          // Add any other emitter settings as needed
        }}
      />
    </>
  );
};

Note:

  • Ensure the GLTF file at /models/sword.glb has a node named Sword.
  • If your model's node hierarchy is different, adjust nodes.Sword.geometry accordingly.

API Reference

VFXParticles Component

| Property | Type | Description | | -------- | ------------- | ------------------------------------------------ | | name | string | Unique identifier for this particle system | | settings | object | Configuration options for particles | | alphaMap | THREE.Texture | Optional texture for particle alpha/transparency | | geometry | ReactElement | Optional custom geometry for particles |

VFXParticles Settings

| Setting | Type | Default | Description | | ------------ | ------------------------ | ---------------- | ---------------------------------------- | | nbParticles | number | 1000 | Maximum number of particles | | intensity | number | 1 | Brightness multiplier | | renderMode | 'billboard' | 'mesh' | 'stretchBillboard' | | fadeSize | [number, number] | [0.1, 0.9] | Size fade in/out range (0-1 of lifetime) | | fadeAlpha | [number, number] | [0, 1.0] | Opacity fade in/out range | | gravity | [number, number, number] | [0, 0, 0] | Gravity force applied to particles | | blendingMode | THREE.Blending | AdditiveBlending | How particles blend with the scene |


VFXEmitter Component

| Property | Type | Description | | -------- | ------- | ------------------------------------------- | | emitter | string | Name of the target particle system | | settings | object | Configuration options for emission behavior | | debug | boolean | Show Leva controls to adjust settings |

VFXEmitter Settings

| Setting | Type | Default | Description | | ----------------- | ------------------------ | ------------------ | ------------------------------------- | | loop | boolean | true | Continuously emit particles | | duration | number | 1 | Emission cycle duration in seconds | | nbParticles | number | 100 | Number of particles to emit per cycle | | spawnMode | 'time' | 'burst' | 'time' | | delay | number | 0 | Time delay before starting emission | | particlesLifetime | [number, number] | [0.1, 1] | Particle lifetime range [min, max] | | startPositionMin | [number, number, number] | [-0.1, -0.1, -0.1] | Minimum start position | | startPositionMax | [number, number, number] | [0.1, 0.1, 0.1] | Maximum start position | | startRotationMin | [number, number, number] | [0, 0, 0] | Minimum start rotation | | startRotationMax | [number, number, number] | [0, 0, 0] | Maximum start rotation | | rotationSpeedMin | [number, number, number] | [0, 0, 0] | Minimum rotation speed | | rotationSpeedMax | [number, number, number] | [0, 0, 0] | Maximum rotation speed | | directionMin | [number, number, number] | [-1, 0, -1] | Minimum emission direction | | directionMax | [number, number, number] | [1, 1, 1] | Maximum emission direction | | size | [number, number] | [0.01, 0.25] | Particle size range [min, max] | | speed | [number, number] | [1, 12] | Particle speed range [min, max] | | colorStart | string[] | ['white'] | Colors at start (randomly selected) | | colorEnd | string[] | ['white'] | Colors at end (randomly selected) |


📄 License

MIT © Dev-Sameerkhan