A beautiful, interactive firework simulator React component. Features 12 shell types, canvas-based particle rendering, sound effects, dynamic sky lighting, and full customization -- all in a single drop-in component.
Ported from the original vanilla JS firework simulator by Caleb Miller.
npm install react-fireworks
# or
yarn add react-fireworks
# or
pnpm add react-fireworks
# or
bun add react-fireworksPeer dependencies: react >= 18 and react-dom >= 18 (React 19 also supported).
import { FireworkSimulator } from 'react-fireworks';
import 'react-fireworks/styles';
function App() {
return <FireworkSimulator style={{ width: '100vw', height: '100vh' }} />;
}That's it -- a full-screen firework show with auto-launching sequences and interactive canvas (click to launch).
<FireworkSimulator style={{ position: 'fixed', inset: 0 }} /><FireworkSimulator
config={{
shell: 'Willow',
size: '4',
quality: '3', // QUALITY_HIGH
skyLighting: '2', // SKY_LIGHT_NORMAL
autoLaunch: true,
finale: false,
}}
style={{ width: '100%', height: 500 }}
/><FireworkSimulator
config={{ backgroundColor: '#1a1a2e' }}
style={{ width: '100vw', height: '100vh' }}
/>Note: Works best with dark colors. The renderer uses
mix-blend-mode: lighten, so very bright backgrounds will make dimmer particles invisible.
<FireworkSimulator soundEnabled style={{ width: '100vw', height: '100vh' }} />import { FireworkSimulator, FireworkEngine } from 'react-fireworks';
import 'react-fireworks/styles';
import { useRef } from 'react';
function App() {
const engineRef = useRef<FireworkEngine | null>(null);
const launchOne = () => {
engineRef.current?.launchShellFromConfig();
};
return (
<>
<FireworkSimulator
paused
onReady={(engine) => { engineRef.current = engine; }}
style={{ width: '100%', height: 400 }}
/>
<button onClick={launchOne}>Launch Firework</button>
</>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
config |
Partial<EngineConfig> |
Device-aware defaults | Engine configuration (merged with defaults). Changes are synced to the engine at runtime. |
className |
string |
undefined |
CSS class name applied to the root container. |
style |
React.CSSProperties |
undefined |
Inline styles for the root container. You must provide dimensions (width/height) since the component fills its container. |
paused |
boolean |
false |
Pause the simulation. |
soundEnabled |
boolean |
false |
Enable sound effects (launch whooshes, burst explosions, crackles). |
launchSequence |
LaunchEntry[] |
undefined |
Custom launch sequence. Shells fire in order, cycling after the last entry. Omit for random mode. |
onReady |
(engine: FireworkEngine) => void |
undefined |
Callback fired when the engine is initialized. Use this to store a reference for programmatic control. |
The EngineConfig interface controls the simulation behavior. Pass any subset as config:
interface EngineConfig {
quality: string; // '1' (Low), '2' (Normal), '3' (High)
shell: string; // Shell type name (see Shell Types below)
size: string; // Shell size: '0'-'5' (maps to 3"-16")
autoLaunch: boolean; // Auto-fire sequences
finale: boolean; // Intense rapid-fire mode (requires autoLaunch)
skyLighting: string; // '0' (None), '1' (Dim), '2' (Normal)
longExposure: boolean; // Camera long-exposure effect
scaleFactor: number; // Zoom level: 0.5 - 2.0
backgroundColor: string; // Hex color for background (default: '#000000')
}The launchSequence prop accepts an array of LaunchEntry objects. When provided, the engine fires shells in the specified order, cycling back to the beginning after the last entry. Omit or pass undefined to use the default random mode.
interface LaunchEntry {
shell: ShellName; // Shell type to launch (required)
size?: number; // Shell size, same scale as EngineConfig.size (default: config.size)
x?: number; // Horizontal position, 0-1 (default: random)
y?: number; // Launch height, 0-1 (default: random)
delay?: number; // Delay in ms before next launch (default: based on shell star life)
}Example -- a choreographed show:
<FireworkSimulator
launchSequence={[
{ shell: 'Crysanthemum', x: 0.5, size: 4 },
{ shell: 'Ring', x: 0.3, delay: 1500 },
{ shell: 'Ring', x: 0.7, delay: 1500 },
{ shell: 'Palm', x: 0.5, size: 3 },
{ shell: 'Willow', x: 0.5, delay: 3000 },
]}
style={{ width: '100vw', height: '100vh' }}
/>Example -- only Crysanthemum and Palm, alternating:
<FireworkSimulator
launchSequence={[
{ shell: 'Crysanthemum' },
{ shell: 'Palm' },
]}
style={{ width: '100vw', height: '100vh' }}
/>The launch sequence can also be set programmatically via the engine:
engine.setLaunchSequence([
{ shell: 'Ring', x: 0.5, delay: 1000 },
{ shell: 'Strobe', x: 0.5, delay: 1000 },
]);
// Clear the sequence to return to random mode
engine.setLaunchSequence([]);The following shell types are available (pass as shell in config):
| Shell | Description |
|---|---|
Random |
Randomly selects from all types (default) |
Crysanthemum |
Classic spherical burst with optional pistil and streamers |
Crackle |
Sparkling crackle effect |
Crossette |
Stars that split into smaller bursts on death |
Falling Leaves |
Slow-drifting leaf-like particles |
Floral |
Flower-pattern burst |
Ghost |
Invisible launch trail, colored burst |
Horse Tail |
Heavy trailing sparks that fall like a horse's tail |
Palm |
Palm-tree shaped burst |
Ring |
Ring-shaped burst pattern |
Strobe |
Blinking strobe effect |
Willow |
Long-trailing willow effect |
Access the full list programmatically:
import { shellNames } from 'react-fireworks';
// ['Random', 'Crackle', 'Crossette', 'Crysanthemum', ...]The FireworkEngine class provides programmatic control over the simulation. Obtain a reference via the onReady prop.
| Method | Signature | Description |
|---|---|---|
setConfig |
(config: Partial<EngineConfig>) => void |
Update engine configuration at runtime. |
setPaused |
(paused: boolean) => void |
Pause or resume the simulation. |
setSoundEnabled |
(enabled: boolean) => void |
Enable or disable sound effects. |
setLaunchSequence |
(sequence: LaunchEntry[]) => void |
Set a custom launch sequence. Pass an empty array to return to random mode. |
handleResize |
() => void |
Recalculate canvas dimensions. Called automatically on window resize. |
launchShellFromConfig |
(event?: { x: number; y: number }) => void |
Launch a single firework. Pass canvas-relative coordinates to target a position, or omit for a random location. |
destroy |
() => void |
Clean up all resources (animation frames, event listeners, particle pools). Called automatically on component unmount. |
Convenience constants for building config objects:
import {
// Quality levels
QUALITY_LOW, // 1
QUALITY_NORMAL, // 2
QUALITY_HIGH, // 3
// Sky lighting levels
SKY_LIGHT_NONE, // 0
SKY_LIGHT_DIM, // 1
SKY_LIGHT_NORMAL, // 2
// Device detection flags
IS_MOBILE,
IS_DESKTOP,
IS_HEADER,
IS_HIGH_END_DEVICE,
// Helpers
getDefaultScaleFactor,
shellNames,
} from 'react-fireworks';For advanced integrations (e.g., building a custom settings UI), the useFireworkStore hook provides state management:
import { useFireworkStore } from 'react-fireworks';
const {
state, // Full AppState object
setPaused, // (paused: boolean) => void
setSoundEnabled, // (enabled: boolean) => void
setConfig, // (config: Partial<EngineConfig>) => void
} = useFireworkStore(/* optional config overrides */);interface AppState {
paused: boolean; // Is the simulation paused?
soundEnabled: boolean; // Are sound effects on?
config: EngineConfig; // Current engine configuration
}- Click or tap anywhere on the canvas to launch a firework at that position.
- Drag along the bottom edge of the canvas to adjust simulation speed (0% - 100%).
The component ships with its own scoped CSS. All internal class names are prefixed with fw- to avoid conflicts with your app's styles.
// Required -- import alongside the component
import 'react-fireworks/styles';The component fills its container. You must provide dimensions via style or className:
// Via inline style
<FireworkSimulator style={{ width: '100%', height: '100vh' }} />
// Via CSS class
<FireworkSimulator className="my-firework-wrapper" />.my-firework-wrapper {
width: 100%;
height: 500px;
}All internal elements use the fw- prefix. Override them with higher-specificity selectors:
/* Remove stage border */
.my-app .fw-stage-container {
border: none;
}To change the background color, use config.backgroundColor rather than CSS overrides -- this ensures the sky lighting effect uses the correct base color.
| Class | Element |
|---|---|
fw-container |
Root wrapper |
fw-stage-container |
Canvas sizing wrapper |
fw-canvas-container |
Canvas element wrapper |
Sound effects (launch whooshes, burst explosions, crackles) are loaded from a CDN on demand. They feature randomized pitch and volume for natural variation. Sound is off by default and can be enabled via the soundEnabled prop or programmatically:
// Via prop
<FireworkSimulator soundEnabled style={{ width: '100vw', height: '100vh' }} />
// Via engine reference
engine.setSoundEnabled(true);- Object pooling: All particles (stars, sparks, burst flashes) use object pools, eliminating garbage collection pressure during animation.
- Dual-canvas rendering: Trails render on a separate canvas from the foreground for efficient compositing with
mix-blend-mode: lighten. - Device-aware defaults: Quality and scale automatically adjust based on screen size and
navigator.hardwareConcurrency. - For constrained environments (low-end devices, small containers), set
quality: '1'and a smallerscaleFactor. - The
finalemode launches fireworks rapidly and may cause lag on lower-end hardware.
Works in all modern browsers supporting:
<canvas>2D rendering contextrequestAnimationFrame- ES2023 syntax (or transpiled by your bundler)
- Web Audio API (optional -- for sound effects; degrades gracefully if unavailable)
# Install dependencies
bun install
# Start dev server (demo app at localhost:5173)
bun dev
# Build the library (outputs to dist/)
bun run build
# Type-check
bun run lintThe src/main.tsx and src/App.tsx files serve as a development playground and are excluded from the library build.
The library separates the imperative canvas engine from the React UI layer:
src/
index.ts # Library entry point (public exports)
firework.css # Scoped component styles (fw- prefix)
components/
FireworkSimulator.tsx # Main component: wires React props to engine
engine/
FireworkEngine.ts # Main orchestrator: animation loop, physics, rendering
Stage.ts # Canvas wrapper (sizing, DPR, pointer events, rAF)
particles.ts # Object-pooled particle systems (Star, Spark, BurstFlash)
shells.ts # 12 shell type factories + Shell class
sound.ts # SoundManager (preload, playback, throttling)
constants.ts # Colors, quality levels, device detection
math.ts # Utility math functions
hooks/
useFireworkStore.ts # State management hook for building custom UIs
Key design decisions:
- The component renders only the canvas -- all UI (controls, settings) is left to the consumer.
- The engine runs outside React's render cycle. React only manages the canvas container.
- State flows one-way: React props ->
useEffect-> engine setter methods. The engine never calls back into React.
MIT
Original firework simulation by Caleb Miller.