@konfetti-js/core 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/shapes.ts","../src/utils.ts","../src/particle.ts","../src/physics.ts","../src/presets.ts","../src/renderer.ts","../src/konfetti.ts","../src/global.ts"],"sourcesContent":["/**\n * konfetti.js\n * A lightweight, performant confetti animation library\n */\n\nexport type { KonfettiInstance } from './global';\nexport {\n cannon,\n continuous,\n create,\n destroy,\n explosion,\n fire,\n fireFromElement,\n firePreset,\n fireworks,\n originFromElement,\n pride,\n rain,\n reset,\n sideCannons,\n snow,\n} from './global';\n// Class for advanced usage (pause/resume, several canvases)\nexport { Konfetti } from './konfetti';\nexport { isPresetName, PRESET_NAMES } from './presets';\nexport type {\n CreateOptions,\n FireFromElementOptions,\n KonfettiOptions,\n Origin,\n PresetName,\n ShapeType,\n} from './types';\n","import type { ShapeType } from './types';\n\n/**\n * Shape rendering functions\n * Each shape function draws centered at (0, 0) with the given size\n */\nexport type ShapeRenderer = (ctx: CanvasRenderingContext2D, size: number) => void;\n\n/**\n * Draw a circle\n */\nfunction drawCircle(ctx: CanvasRenderingContext2D, size: number): void {\n ctx.beginPath();\n ctx.arc(0, 0, size / 2, 0, Math.PI * 2);\n ctx.fill();\n}\n\n/**\n * Draw a square\n */\nfunction drawSquare(ctx: CanvasRenderingContext2D, size: number): void {\n const halfSize = size / 2;\n ctx.fillRect(-halfSize, -halfSize, size, size);\n}\n\n/**\n * Supported shapes; a particle stores its shape as an index into this list\n */\nconst SHAPES: readonly ShapeType[] = ['circle', 'square'];\n\nconst RENDERERS: readonly ShapeRenderer[] = [drawCircle, drawSquare];\n\n/**\n * Whether a value is a supported shape name\n */\nexport function isShape(value: unknown): value is ShapeType {\n return SHAPES.includes(value as ShapeType);\n}\n\n/**\n * Shape index for Float32Array storage\n */\nexport function shapeToIndex(shape: ShapeType): number {\n return Math.max(0, SHAPES.indexOf(shape));\n}\n\n/**\n * Get the renderer for a stored shape index\n */\nexport function getShapeRenderer(index: number): ShapeRenderer {\n return RENDERERS[index] ?? drawCircle;\n}\n","import { isShape } from './shapes';\nimport type { KonfettiOptions, Origin, ResolvedOptions, ShapeType } from './types';\n\n/**\n * Default festive colors\n */\nexport const DEFAULT_COLORS = [\n '#26ccff', // cyan\n '#a25afd', // purple\n '#ff5e7e', // pink\n '#88ff5a', // green\n '#fcff42', // yellow\n '#ffa62d', // orange\n '#ff36ff', // magenta\n];\n\n/**\n * Default options\n */\nexport const DEFAULT_OPTIONS: ResolvedOptions = {\n particleCount: 50,\n angle: 90,\n spread: 45,\n startVelocity: 45,\n decay: 0.9,\n gravity: 1,\n drift: 0,\n ticks: 200,\n origin: { x: 0.5, y: 0.5 },\n colors: DEFAULT_COLORS,\n shapes: ['circle', 'square'] as ShapeType[],\n scalar: 1,\n zIndex: 100,\n disableForReducedMotion: true,\n};\n\n/**\n * Use `value` when it is a finite number, otherwise `fallback`\n */\nfunction finite(value: unknown, fallback: number): number {\n return typeof value === 'number' && Number.isFinite(value) ? value : fallback;\n}\n\n/**\n * Merge user options with defaults, replacing missing or invalid values\n */\nexport function resolveOptions(options: KonfettiOptions = {}): ResolvedOptions {\n const d = DEFAULT_OPTIONS;\n const colors = Array.isArray(options.colors)\n ? options.colors.filter((c) => typeof c === 'string' && c.length > 0)\n : [];\n const shapes = Array.isArray(options.shapes) ? options.shapes.filter(isShape) : [];\n\n return {\n particleCount: Math.max(0, Math.round(finite(options.particleCount, d.particleCount))),\n angle: finite(options.angle, d.angle),\n spread: finite(options.spread, d.spread),\n startVelocity: finite(options.startVelocity, d.startVelocity),\n decay: clamp(finite(options.decay, d.decay), 0, 1),\n gravity: finite(options.gravity, d.gravity),\n drift: finite(options.drift, d.drift),\n ticks: Math.max(1, finite(options.ticks, d.ticks)),\n origin: {\n x: finite(options.origin?.x, d.origin.x),\n y: finite(options.origin?.y, d.origin.y),\n },\n colors: colors.length > 0 ? colors : [...d.colors],\n shapes: shapes.length > 0 ? shapes : [...d.shapes],\n scalar: Math.max(0, finite(options.scalar, d.scalar)),\n zIndex: finite(options.zIndex, d.zIndex),\n disableForReducedMotion: options.disableForReducedMotion ?? d.disableForReducedMotion,\n };\n}\n\n/**\n * Layer `override` on top of `base`, skipping keys that are explicitly undefined\n * so a wrapper passing `{ colors: undefined }` keeps the preset's colors\n */\nexport function mergeOptions(base: KonfettiOptions, override?: KonfettiOptions): KonfettiOptions {\n const merged: Record<string, unknown> = { ...base };\n if (override) {\n for (const [key, value] of Object.entries(override)) {\n if (value !== undefined) merged[key] = value;\n }\n // Origins merge per axis, so { x: 0.2 } keeps the base's y\n if (override.origin) merged.origin = mergeOrigin(base.origin, override.origin);\n }\n return merged as KonfettiOptions;\n}\n\n/**\n * Layer the defined axes of `override` on top of `base`\n */\nexport function mergeOrigin(\n base: Partial<Origin> | undefined,\n override: Partial<Origin> | undefined\n): Partial<Origin> {\n return {\n ...base,\n ...(override?.x !== undefined && { x: override.x }),\n ...(override?.y !== undefined && { y: override.y }),\n };\n}\n\n/**\n * Convert degrees to radians\n */\nexport function degToRad(deg: number): number {\n return deg * (Math.PI / 180);\n}\n\n/**\n * Get random number between min and max\n */\nexport function randomRange(min: number, max: number): number {\n return Math.random() * (max - min) + min;\n}\n\n/**\n * Get random item from array\n */\nexport function randomItem<T>(arr: readonly T[]): T {\n return arr[Math.floor(Math.random() * arr.length)];\n}\n\n/**\n * Whether we are running in a browser with a DOM\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if user prefers reduced motion\n */\nexport function prefersReducedMotion(): boolean {\n if (typeof window === 'undefined') return false;\n const mediaQuery = window.matchMedia?.('(prefers-reduced-motion: reduce)');\n return mediaQuery?.matches ?? false;\n}\n\n/**\n * Clamp a value between min and max\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n","import { shapeToIndex } from './shapes';\nimport { ParticleIndex, type ResolvedOptions } from './types';\nimport { degToRad, randomItem, randomRange } from './utils';\n\n/** Hard upper limit, so a runaway loop of fire() calls cannot eat memory */\nexport const MAX_PARTICLES = 10_000;\n\n/** Above this many colors, unused ones are dropped from the palette */\nconst MAX_PALETTE = 256;\n\n/**\n * Particle pool using Float32Array for performance\n * Each particle uses ParticleIndex.SIZE floats\n */\nexport class ParticlePool {\n /** Raw particle data */\n public data: Float32Array;\n /** Number of active particles */\n public activeCount = 0;\n /**\n * Colors in use; particles store an index into this list, so any CSS color\n * works without parsing it\n */\n public readonly palette: string[] = [];\n private readonly colorIds = new Map<string, number>();\n\n constructor(initialCapacity = 512) {\n this.data = new Float32Array(initialCapacity * ParticleIndex.SIZE);\n }\n\n /** How many particles fit before the buffer has to grow */\n get capacity(): number {\n return this.data.length / ParticleIndex.SIZE;\n }\n\n /**\n * Remove every particle\n */\n reset(): void {\n this.activeCount = 0;\n this.clearPalette();\n }\n\n /**\n * Spawn particles with the given options\n */\n spawn(options: ResolvedOptions, canvasWidth: number, canvasHeight: number): void {\n const count = Math.min(options.particleCount, MAX_PARTICLES - this.activeCount);\n if (count <= 0) return;\n this.ensureCapacity(this.activeCount + count);\n\n const data = this.data;\n const originX = options.origin.x * canvasWidth;\n const originY = options.origin.y * canvasHeight;\n const angleRad = degToRad(options.angle);\n const spreadRad = degToRad(options.spread);\n\n for (let i = 0; i < count; i++) {\n const idx = (this.activeCount + i) * ParticleIndex.SIZE;\n\n // Random angle within spread\n const particleAngle = angleRad + randomRange(-spreadRad / 2, spreadRad / 2);\n // Random velocity variation\n const velocity = options.startVelocity * randomRange(0.5, 1);\n\n // Position\n data[idx + ParticleIndex.X] = originX;\n data[idx + ParticleIndex.Y] = originY;\n\n // Velocity (negative Y because canvas Y is inverted)\n data[idx + ParticleIndex.VelocityX] = Math.cos(particleAngle) * velocity;\n data[idx + ParticleIndex.VelocityY] = -Math.sin(particleAngle) * velocity;\n\n // Rotation\n data[idx + ParticleIndex.Rotation] = randomRange(0, Math.PI * 2);\n data[idx + ParticleIndex.RotationSpeed] = randomRange(-0.1, 0.1);\n\n // Tilt (for wobble effect)\n data[idx + ParticleIndex.Tilt] = randomRange(0, Math.PI * 2);\n data[idx + ParticleIndex.TiltSpeed] = randomRange(0.05, 0.15);\n\n data[idx + ParticleIndex.Color] = this.colorId(randomItem(options.colors));\n data[idx + ParticleIndex.Shape] = shapeToIndex(randomItem(options.shapes));\n\n // Scalar (size)\n data[idx + ParticleIndex.Scalar] = options.scalar * randomRange(0.8, 1.2);\n\n // Life\n data[idx + ParticleIndex.Life] = options.ticks;\n data[idx + ParticleIndex.MaxLife] = options.ticks;\n\n // Physics are stored per particle so each burst keeps its own settings\n data[idx + ParticleIndex.Drift] = options.drift + randomRange(-0.5, 0.5);\n data[idx + ParticleIndex.Gravity] = options.gravity;\n data[idx + ParticleIndex.Decay] = options.decay;\n }\n\n this.activeCount += count;\n }\n\n /**\n * Remove dead particles, keeping live ones packed at the front\n */\n compact(): void {\n const data = this.data;\n let writeIdx = 0;\n\n for (let readIdx = 0; readIdx < this.activeCount; readIdx++) {\n const srcIdx = readIdx * ParticleIndex.SIZE;\n if (data[srcIdx + ParticleIndex.Life] <= 0) continue;\n\n if (writeIdx !== readIdx) {\n const dstIdx = writeIdx * ParticleIndex.SIZE;\n data.copyWithin(dstIdx, srcIdx, srcIdx + ParticleIndex.SIZE);\n }\n writeIdx++;\n }\n\n this.activeCount = writeIdx;\n if (writeIdx === 0) {\n this.clearPalette();\n } else if (this.palette.length > MAX_PALETTE) {\n this.prunePalette();\n }\n }\n\n /**\n * Keep only colors that live particles still use, renumbering them, so a long\n * stream with random colors does not grow the palette forever\n */\n private prunePalette(): void {\n const data = this.data;\n const oldPalette = [...this.palette];\n const remap = new Map<number, number>();\n this.clearPalette();\n\n for (let i = 0; i < this.activeCount; i++) {\n const idx = i * ParticleIndex.SIZE + ParticleIndex.Color;\n const oldId = data[idx];\n let newId = remap.get(oldId);\n if (newId === undefined) {\n newId = this.colorId(oldPalette[oldId]);\n remap.set(oldId, newId);\n }\n data[idx] = newId;\n }\n }\n\n private colorId(color: string): number {\n let id = this.colorIds.get(color);\n if (id === undefined) {\n id = this.palette.length;\n this.palette.push(color);\n this.colorIds.set(color, id);\n }\n return id;\n }\n\n private clearPalette(): void {\n this.palette.length = 0;\n this.colorIds.clear();\n }\n\n private ensureCapacity(needed: number): void {\n if (needed <= this.capacity) return;\n let capacity = this.capacity;\n while (capacity < needed) capacity *= 2;\n const grown = new Float32Array(Math.min(capacity, MAX_PARTICLES) * ParticleIndex.SIZE);\n grown.set(this.data.subarray(0, this.activeCount * ParticleIndex.SIZE));\n this.data = grown;\n }\n}\n","import type { ParticlePool } from './particle';\nimport { ParticleIndex } from './types';\n\n/**\n * Advance every particle by `dt`, measured in 60 fps frames (1 = 16.7 ms), so\n * motion and lifetime look the same at any refresh rate.\n * Returns true if there are still active particles.\n */\nexport function updateParticles(pool: ParticlePool, dt: number): boolean {\n const data = pool.data;\n\n for (let i = 0; i < pool.activeCount; i++) {\n const idx = i * ParticleIndex.SIZE;\n\n let vx = data[idx + ParticleIndex.VelocityX];\n let vy = data[idx + ParticleIndex.VelocityY];\n const tilt = data[idx + ParticleIndex.Tilt];\n\n // Gravity, then horizontal wobble based on tilt\n vy += data[idx + ParticleIndex.Gravity] * dt;\n vx += data[idx + ParticleIndex.Drift] * Math.sin(tilt) * dt;\n\n // Air resistance: decay is the share of speed kept per 60 fps frame\n const damping = data[idx + ParticleIndex.Decay] ** dt;\n vx *= damping;\n vy *= damping;\n\n data[idx + ParticleIndex.VelocityX] = vx;\n data[idx + ParticleIndex.VelocityY] = vy;\n data[idx + ParticleIndex.X] += vx * dt;\n data[idx + ParticleIndex.Y] += vy * dt;\n data[idx + ParticleIndex.Rotation] += data[idx + ParticleIndex.RotationSpeed] * dt;\n data[idx + ParticleIndex.Tilt] = tilt + data[idx + ParticleIndex.TiltSpeed] * dt;\n data[idx + ParticleIndex.Life] -= dt;\n }\n\n // Remove dead particles\n pool.compact();\n\n return pool.activeCount > 0;\n}\n","import type { KonfettiOptions, PresetName } from './types';\n\n/**\n * One burst of a preset, fired `delay` ms after the preset starts\n */\ninterface PresetBurst {\n delay?: number;\n options: KonfettiOptions;\n}\n\ninterface PresetDefinition {\n bursts: readonly PresetBurst[];\n /**\n * Whether the preset is a single burst that can be moved to a caller's origin\n * (for example an element). Screen-wide presets keep their own positions.\n */\n followsOrigin: boolean;\n}\n\nconst FIREWORK_COLORS = ['#ff0000', '#ffff00', '#00ff00', '#00ffff', '#ff00ff'];\nconst FIREWORK: KonfettiOptions = {\n particleCount: 80,\n angle: 90,\n spread: 360,\n startVelocity: 35,\n decay: 0.91,\n gravity: 1,\n colors: FIREWORK_COLORS,\n};\n\nconst PRIDE_COLORS = [\n '#e40303', // red\n '#ff8c00', // orange\n '#ffed00', // yellow\n '#008026', // green\n '#004dff', // blue\n '#750787', // purple\n];\n\n/**\n * Built-in preset effects\n */\nexport const PRESETS: Readonly<Record<PresetName, PresetDefinition>> = {\n // Burst of confetti from bottom center shooting up\n cannon: {\n followsOrigin: true,\n bursts: [\n {\n options: {\n particleCount: 100,\n angle: 90,\n spread: 70,\n startVelocity: 50,\n decay: 0.91,\n gravity: 1,\n origin: { x: 0.5, y: 1 },\n },\n },\n ],\n },\n // 360 degree burst from center\n explosion: {\n followsOrigin: true,\n bursts: [\n {\n options: {\n particleCount: 150,\n angle: 90,\n spread: 360,\n startVelocity: 40,\n decay: 0.92,\n gravity: 0.8,\n origin: { x: 0.5, y: 0.5 },\n },\n },\n ],\n },\n // Three bursts across the top half\n fireworks: {\n followsOrigin: false,\n bursts: [\n { delay: 0, options: { ...FIREWORK, origin: { x: 0.3, y: 0.4 } } },\n { delay: 150, options: { ...FIREWORK, origin: { x: 0.5, y: 0.3 } } },\n { delay: 300, options: { ...FIREWORK, origin: { x: 0.7, y: 0.4 } } },\n ],\n },\n // Particles falling from the top\n rain: {\n followsOrigin: false,\n bursts: [\n {\n options: {\n particleCount: 50,\n angle: 270,\n spread: 60,\n startVelocity: 10,\n decay: 0.95,\n gravity: 0.5,\n drift: 0,\n origin: { x: 0.5, y: 0 },\n ticks: 300,\n },\n },\n ],\n },\n // Gentle falling white flakes\n snow: {\n followsOrigin: false,\n bursts: [\n {\n options: {\n particleCount: 30,\n angle: 270,\n spread: 120,\n startVelocity: 5,\n decay: 0.98,\n gravity: 0.3,\n drift: 1,\n origin: { x: 0.5, y: -0.1 },\n ticks: 400,\n colors: ['#ffffff', '#e0e0e0', '#c0c0c0'],\n shapes: ['circle'],\n },\n },\n ],\n },\n // Bursts from both sides\n sideCannons: {\n followsOrigin: false,\n bursts: [\n {\n options: {\n particleCount: 50,\n angle: 60,\n spread: 55,\n startVelocity: 50,\n origin: { x: 0, y: 0.7 },\n },\n },\n {\n options: {\n particleCount: 50,\n angle: 120,\n spread: 55,\n startVelocity: 50,\n origin: { x: 1, y: 0.7 },\n },\n },\n ],\n },\n // Rainbow colors\n pride: {\n followsOrigin: true,\n bursts: [\n {\n options: {\n particleCount: 100,\n spread: 70,\n origin: { x: 0.5, y: 0.6 },\n colors: PRIDE_COLORS,\n },\n },\n ],\n },\n};\n\n/**\n * Defaults for continuous(): a small burst from the bottom every interval\n */\nexport const CONTINUOUS_DEFAULTS: KonfettiOptions = {\n particleCount: 10,\n angle: 90,\n spread: 55,\n startVelocity: 45,\n origin: { x: 0.5, y: 1 },\n};\n\n/**\n * Names of all built-in presets\n */\nexport const PRESET_NAMES = Object.keys(PRESETS) as readonly PresetName[];\n\n/**\n * Whether a value names a built-in preset (useful for attribute or prop values)\n */\nexport function isPresetName(value: unknown): value is PresetName {\n return typeof value === 'string' && (PRESET_NAMES as readonly string[]).includes(value);\n}\n","import type { ParticlePool } from './particle';\nimport { getShapeRenderer } from './shapes';\nimport { ParticleIndex } from './types';\n\n/** Base particle size in CSS pixels */\nconst BASE_SIZE = 10;\n\n/**\n * Create a full-screen overlay canvas that never blocks the page\n */\nfunction createOverlayCanvas(): HTMLCanvasElement {\n const canvas = document.createElement('canvas');\n canvas.className = 'konfetti-canvas';\n canvas.setAttribute('aria-hidden', 'true');\n Object.assign(canvas.style, {\n position: 'fixed',\n top: '0',\n left: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: '100',\n });\n document.body.appendChild(canvas);\n return canvas;\n}\n\n/**\n * Canvas renderer for particles\n */\nexport class Renderer {\n private readonly canvas: HTMLCanvasElement;\n private readonly ctx: CanvasRenderingContext2D | null;\n /** True when we created the canvas, so we may style and remove it */\n private readonly ownsCanvas: boolean;\n /** Size in CSS pixels; the backing store is this times the pixel ratio */\n private width = 0;\n private height = 0;\n private pixelRatio = 1;\n /** Particle indices grouped by palette color, reused between frames */\n private readonly buckets: number[][] = [];\n\n constructor(canvas?: HTMLCanvasElement) {\n this.ownsCanvas = !canvas;\n this.canvas = canvas ?? createOverlayCanvas();\n this.ctx = this.canvas.getContext('2d');\n this.resize();\n }\n\n /**\n * Match the canvas to its display size. The full-screen canvas also renders at\n * the screen's pixel density; a canvas you pass in keeps one pixel per CSS\n * pixel, because without a CSS size its display size follows its pixel size\n * and would grow on every resize.\n */\n resize(): void {\n if (this.ownsCanvas) {\n this.width = window.innerWidth;\n this.height = window.innerHeight;\n this.pixelRatio = window.devicePixelRatio || 1;\n } else {\n const rect = this.canvas.getBoundingClientRect();\n this.width = rect.width;\n this.height = rect.height;\n this.pixelRatio = 1;\n }\n this.canvas.width = Math.round(this.width * this.pixelRatio);\n this.canvas.height = Math.round(this.height * this.pixelRatio);\n }\n\n /**\n * Canvas size in CSS pixels\n */\n getDimensions(): { width: number; height: number } {\n return { width: this.width, height: this.height };\n }\n\n /**\n * Set the stacking order; only applies to the full-screen canvas we own\n */\n setZIndex(zIndex: number): void {\n if (this.ownsCanvas) this.canvas.style.zIndex = String(zIndex);\n }\n\n /**\n * Clear the canvas\n */\n clear(): void {\n if (!this.ctx) return;\n this.ctx.setTransform(1, 0, 0, 1, 0, 0);\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n }\n\n /**\n * Draw all particles, batched by color to limit fillStyle changes\n */\n render(pool: ParticlePool): void {\n this.clear();\n const ctx = this.ctx;\n if (!ctx) return;\n\n const data = pool.data;\n const ratio = this.pixelRatio;\n const buckets = this.buckets;\n\n for (const bucket of buckets) bucket.length = 0;\n for (let i = 0; i < pool.activeCount; i++) {\n const colorId = data[i * ParticleIndex.SIZE + ParticleIndex.Color];\n if (!buckets[colorId]) buckets[colorId] = [];\n buckets[colorId].push(i);\n }\n\n for (let colorId = 0; colorId < buckets.length; colorId++) {\n const bucket = buckets[colorId];\n if (!bucket || bucket.length === 0) continue;\n ctx.fillStyle = pool.palette[colorId];\n\n for (const particle of bucket) {\n const idx = particle * ParticleIndex.SIZE;\n const tilt = data[idx + ParticleIndex.Tilt];\n const rotation = data[idx + ParticleIndex.Rotation];\n\n // Fade out over the last half of the particle's life\n const opacity = Math.min(\n 1,\n (data[idx + ParticleIndex.Life] / data[idx + ParticleIndex.MaxLife]) * 2\n );\n const size = BASE_SIZE * data[idx + ParticleIndex.Scalar] * (0.8 + 0.2 * Math.cos(tilt));\n if (size < 0.5 || opacity < 0.01) continue;\n\n // translate(x, y) · rotate(rotation) · scale(1, squash), scaled to device pixels.\n // Setting the matrix directly avoids a save()/restore() per particle.\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const squash = 0.6 + 0.4 * Math.abs(Math.cos(tilt));\n ctx.globalAlpha = opacity;\n ctx.setTransform(\n ratio * cos,\n ratio * sin,\n -ratio * sin * squash,\n ratio * cos * squash,\n ratio * data[idx + ParticleIndex.X],\n ratio * data[idx + ParticleIndex.Y]\n );\n getShapeRenderer(data[idx + ParticleIndex.Shape])(ctx, size);\n }\n }\n\n ctx.globalAlpha = 1;\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n }\n\n /**\n * Destroy renderer and remove the canvas if we created it\n */\n destroy(): void {\n this.clear();\n if (this.ownsCanvas) this.canvas.remove();\n }\n}\n","import { ParticlePool } from './particle';\nimport { updateParticles } from './physics';\nimport { CONTINUOUS_DEFAULTS, isPresetName, PRESETS } from './presets';\nimport { Renderer } from './renderer';\nimport type { CreateOptions, KonfettiOptions, PresetName } from './types';\nimport { clamp, isBrowser, mergeOptions, prefersReducedMotion, resolveOptions } from './utils';\n\n/** Length of one 60 fps frame; physics are tuned in these units */\nconst FRAME_MS = 1000 / 60;\n/** Largest step per frame, so a long stall does not teleport particles */\nconst MAX_STEP = 4;\n\n/**\n * Manages one canvas: the animation loop, particles, physics and rendering.\n * Safe to construct on the server, where every method does nothing.\n */\nexport class Konfetti {\n private readonly pool = new ParticlePool();\n private readonly renderer: Renderer | null = null;\n private frameId: number | null = null;\n /** Timestamp of the previous frame, or when the loop was scheduled */\n private lastTime = 0;\n private paused = false;\n private destroyed = false;\n private readonly resizeWithWindow: boolean = false;\n private readonly timeouts = new Set<ReturnType<typeof setTimeout>>();\n private readonly intervals = new Set<ReturnType<typeof setInterval>>();\n\n constructor(canvas?: HTMLCanvasElement, createOptions: CreateOptions = {}) {\n if (!isBrowser()) {\n this.destroyed = true;\n return;\n }\n\n this.renderer = new Renderer(canvas);\n this.resizeWithWindow = createOptions.resize !== false;\n if (this.resizeWithWindow) window.addEventListener('resize', this.handleResize);\n document.addEventListener('visibilitychange', this.handleVisibilityChange);\n }\n\n /**\n * Fire one burst. Skipped while the page is hidden, after destroy(), and for\n * visitors who prefer reduced motion (unless disableForReducedMotion is false).\n */\n fire(options?: KonfettiOptions): void {\n if (this.destroyed || !this.renderer || document.hidden) return;\n\n const resolved = resolveOptions(options);\n if (resolved.disableForReducedMotion && prefersReducedMotion()) return;\n\n this.renderer.setZIndex(resolved.zIndex);\n const { width, height } = this.renderer.getDimensions();\n this.pool.spawn(resolved, width, height);\n this.scheduleFrame();\n }\n\n /**\n * Fire a built-in preset; options override the preset's own values\n */\n preset(name: PresetName, options?: KonfettiOptions): void {\n if (!isPresetName(name) || this.destroyed) return;\n\n for (const burst of PRESETS[name].bursts) {\n const merged = mergeOptions(burst.options, options);\n if (burst.delay) {\n const id = setTimeout(() => {\n this.timeouts.delete(id);\n this.fire(merged);\n }, burst.delay);\n this.timeouts.add(id);\n } else {\n this.fire(merged);\n }\n }\n }\n\n /**\n * Fire a small burst every `interval` ms until the returned function is\n * called, or until reset() or destroy()\n */\n continuous(options?: KonfettiOptions, interval = 250): () => void {\n if (this.destroyed) return () => {};\n\n const merged = mergeOptions(CONTINUOUS_DEFAULTS, options);\n const delay = Number.isFinite(interval) && interval >= 16 ? interval : 250;\n const id = setInterval(() => this.fire(merged), delay);\n this.intervals.add(id);\n\n return () => {\n clearInterval(id);\n this.intervals.delete(id);\n };\n }\n\n /**\n * Pause the animation; particles stay where they are\n */\n pause(): void {\n this.paused = true;\n this.cancelFrame();\n }\n\n /**\n * Resume after pause()\n */\n resume(): void {\n this.paused = false;\n this.scheduleFrame();\n }\n\n /**\n * Clear all particles, cancel scheduled bursts and streams, stop animating and\n * undo pause()\n */\n reset(): void {\n this.paused = false;\n this.cancelFrame();\n for (const id of this.timeouts) clearTimeout(id);\n for (const id of this.intervals) clearInterval(id);\n this.timeouts.clear();\n this.intervals.clear();\n this.pool.reset();\n this.renderer?.clear();\n }\n\n /**\n * Reset, remove listeners and remove the canvas if this instance created it.\n * The instance ignores every call afterwards.\n */\n destroy(): void {\n if (this.destroyed) return;\n this.reset();\n this.destroyed = true;\n\n if (this.resizeWithWindow) window.removeEventListener('resize', this.handleResize);\n document.removeEventListener('visibilitychange', this.handleVisibilityChange);\n this.renderer?.destroy();\n }\n\n private readonly handleResize = (): void => {\n this.renderer?.resize();\n };\n\n private readonly handleVisibilityChange = (): void => {\n if (document.hidden) {\n this.cancelFrame();\n } else {\n this.scheduleFrame();\n }\n };\n\n /**\n * Start the loop if there is something to animate and nothing prevents it\n */\n private scheduleFrame(): void {\n if (\n this.frameId !== null ||\n this.paused ||\n this.destroyed ||\n document.hidden ||\n this.pool.activeCount === 0\n ) {\n return;\n }\n this.lastTime = performance.now();\n this.frameId = requestAnimationFrame(this.tick);\n }\n\n private cancelFrame(): void {\n if (this.frameId !== null) {\n cancelAnimationFrame(this.frameId);\n this.frameId = null;\n }\n }\n\n private readonly tick = (time: number): void => {\n this.frameId = null;\n if (!this.renderer) return;\n\n const dt = clamp((time - this.lastTime) / FRAME_MS, 0, MAX_STEP);\n this.lastTime = time;\n\n const hasParticles = updateParticles(this.pool, dt);\n this.renderer.render(this.pool);\n\n if (hasParticles) {\n this.frameId = requestAnimationFrame(this.tick);\n }\n };\n}\n","import { Konfetti } from './konfetti';\nimport { isPresetName, PRESETS } from './presets';\nimport type {\n CreateOptions,\n FireFromElementOptions,\n KonfettiOptions,\n Origin,\n PresetName,\n} from './types';\nimport { isBrowser, mergeOrigin } from './utils';\n\n/**\n * Fire function bound to a canvas, with preset, reset and destroy methods\n */\nexport interface KonfettiInstance {\n (options?: KonfettiOptions): void;\n /** Fire a built-in preset into this canvas */\n preset: (name: PresetName, options?: KonfettiOptions) => void;\n /** Fire a stream into this canvas; returns a function that stops it */\n continuous: (options?: KonfettiOptions, interval?: number) => () => void;\n /** Clear the canvas and cancel scheduled bursts */\n reset: () => void;\n /** Stop for good and release listeners */\n destroy: () => void;\n}\n\n// Global instance for the simple API, created on first use\nlet globalInstance: Konfetti | null = null;\n\nfunction getGlobalInstance(): Konfetti | null {\n if (!isBrowser()) return null;\n globalInstance ??= new Konfetti();\n return globalInstance;\n}\n\n/**\n * Fire konfetti on the full-screen canvas\n */\nexport function fire(options?: KonfettiOptions): void {\n getGlobalInstance()?.fire(options);\n}\n\n/**\n * Fire a built-in preset on the full-screen canvas\n */\nexport function firePreset(name: PresetName, options?: KonfettiOptions): void {\n getGlobalInstance()?.preset(name, options);\n}\n\n/**\n * The center of an element, as an origin relative to the viewport\n */\nexport function originFromElement(element: Element): Origin {\n const rect = element.getBoundingClientRect();\n return {\n x: (rect.left + rect.width / 2) / window.innerWidth,\n y: (rect.top + rect.height / 2) / window.innerHeight,\n };\n}\n\n/**\n * Fire from the center of an element, for example the button that was clicked.\n * Single-burst presets (cannon, explosion, pride) start at the element too;\n * screen-wide presets (fireworks, rain, snow, sideCannons) keep their positions.\n * An origin you pass yourself wins, axis by axis.\n */\nexport function fireFromElement(element: Element, options: FireFromElementOptions = {}): void {\n if (!isBrowser()) return;\n\n const { preset: name, ...rest } = options;\n // An unknown name (for example a typo in plain JavaScript) fires a plain burst\n const preset = isPresetName(name) ? name : undefined;\n const followsOrigin = preset ? PRESETS[preset].followsOrigin : true;\n const merged = followsOrigin\n ? { ...rest, origin: mergeOrigin(originFromElement(element), rest.origin) }\n : rest;\n\n if (preset) {\n firePreset(preset, merged);\n } else {\n fire(merged);\n }\n}\n\n/**\n * Clear the full-screen canvas and cancel scheduled bursts and streams\n */\nexport function reset(): void {\n globalInstance?.reset();\n}\n\n/**\n * Remove the full-screen canvas and its listeners; the next fire() creates a new one\n */\nexport function destroy(): void {\n globalInstance?.destroy();\n globalInstance = null;\n}\n\n/**\n * Create a konfetti instance that draws into your own canvas\n */\nexport function create(canvas: HTMLCanvasElement, createOptions?: CreateOptions): KonfettiInstance {\n const instance = new Konfetti(canvas, createOptions);\n\n const fireFn = ((options?: KonfettiOptions) => instance.fire(options)) as KonfettiInstance;\n fireFn.preset = (name, options) => instance.preset(name, options);\n fireFn.continuous = (options, interval) => instance.continuous(options, interval);\n fireFn.reset = () => instance.reset();\n fireFn.destroy = () => instance.destroy();\n\n return fireFn;\n}\n\n/**\n * Fire a steady stream on the full-screen canvas. Returns a function that stops it.\n */\nexport function continuous(options?: KonfettiOptions, interval?: number): () => void {\n return getGlobalInstance()?.continuous(options, interval) ?? (() => {});\n}\n\n/** Burst of confetti from bottom center shooting up */\nexport const cannon = (options?: KonfettiOptions): void => firePreset('cannon', options);\n\n/** 360 degree burst from center */\nexport const explosion = (options?: KonfettiOptions): void => firePreset('explosion', options);\n\n/** Three quick bursts across the top half */\nexport const fireworks = (options?: KonfettiOptions): void => firePreset('fireworks', options);\n\n/** Particles falling from the top */\nexport const rain = (options?: KonfettiOptions): void => firePreset('rain', options);\n\n/** Gentle falling white flakes */\nexport const snow = (options?: KonfettiOptions): void => firePreset('snow', options);\n\n/** Bursts from both sides */\nexport const sideCannons = (options?: KonfettiOptions): void => firePreset('sideCannons', options);\n\n/** Rainbow colors */\nexport const pride = (options?: KonfettiOptions): void => firePreset('pride', options);\n"],"mappings":"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","names":[]}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Shape type for particles
3
+ */
4
+ type ShapeType = 'circle' | 'square';
5
+ /**
6
+ * Origin point (0-1 relative to canvas dimensions)
7
+ */
8
+ interface Origin {
9
+ x: number;
10
+ y: number;
11
+ }
12
+ /**
13
+ * Configuration options for konfetti
14
+ */
15
+ interface KonfettiOptions {
16
+ /** Number of particles to emit (default: 50) */
17
+ particleCount?: number;
18
+ /** Launch angle in degrees, 90 is straight up (default: 90) */
19
+ angle?: number;
20
+ /** Spread angle in degrees (default: 45) */
21
+ spread?: number;
22
+ /** Initial velocity in pixels per frame at 60 fps (default: 45) */
23
+ startVelocity?: number;
24
+ /** Velocity kept per frame at 60 fps, 0-1, lower = faster slowdown (default: 0.9) */
25
+ decay?: number;
26
+ /** Gravity strength (default: 1) */
27
+ gravity?: number;
28
+ /** Horizontal drift (default: 0) */
29
+ drift?: number;
30
+ /** Particle lifetime in frames at 60 fps (default: 200) */
31
+ ticks?: number;
32
+ /**
33
+ * Spawn origin point, 0-1 relative (default: { x: 0.5, y: 0.5 }). An axis you
34
+ * leave out keeps the preset's or default value.
35
+ */
36
+ origin?: Partial<Origin>;
37
+ /** Array of CSS color strings (default: festive colors) */
38
+ colors?: string[];
39
+ /** Particle shapes to use (default: ['circle', 'square']) */
40
+ shapes?: ShapeType[];
41
+ /** Size multiplier (default: 1) */
42
+ scalar?: number;
43
+ /** z-index of the full-screen canvas (default: 100) */
44
+ zIndex?: number;
45
+ /** Disable animation for users who prefer reduced motion (default: true) */
46
+ disableForReducedMotion?: boolean;
47
+ }
48
+ /**
49
+ * Names of the built-in preset effects
50
+ */
51
+ type PresetName = 'cannon' | 'explosion' | 'fireworks' | 'rain' | 'snow' | 'sideCannons' | 'pride';
52
+ /**
53
+ * Options for firing from an element, optionally with a preset
54
+ */
55
+ interface FireFromElementOptions extends KonfettiOptions {
56
+ /** Preset to fire instead of a plain burst */
57
+ preset?: PresetName;
58
+ }
59
+ /**
60
+ * Options for creating a custom konfetti instance
61
+ */
62
+ interface CreateOptions {
63
+ /** Resize the canvas when the window resizes (default: true) */
64
+ resize?: boolean;
65
+ }
66
+
67
+ /**
68
+ * Fire function bound to a canvas, with preset, reset and destroy methods
69
+ */
70
+ interface KonfettiInstance {
71
+ (options?: KonfettiOptions): void;
72
+ /** Fire a built-in preset into this canvas */
73
+ preset: (name: PresetName, options?: KonfettiOptions) => void;
74
+ /** Fire a stream into this canvas; returns a function that stops it */
75
+ continuous: (options?: KonfettiOptions, interval?: number) => () => void;
76
+ /** Clear the canvas and cancel scheduled bursts */
77
+ reset: () => void;
78
+ /** Stop for good and release listeners */
79
+ destroy: () => void;
80
+ }
81
+ /**
82
+ * Fire konfetti on the full-screen canvas
83
+ */
84
+ declare function fire(options?: KonfettiOptions): void;
85
+ /**
86
+ * Fire a built-in preset on the full-screen canvas
87
+ */
88
+ declare function firePreset(name: PresetName, options?: KonfettiOptions): void;
89
+ /**
90
+ * The center of an element, as an origin relative to the viewport
91
+ */
92
+ declare function originFromElement(element: Element): Origin;
93
+ /**
94
+ * Fire from the center of an element, for example the button that was clicked.
95
+ * Single-burst presets (cannon, explosion, pride) start at the element too;
96
+ * screen-wide presets (fireworks, rain, snow, sideCannons) keep their positions.
97
+ * An origin you pass yourself wins, axis by axis.
98
+ */
99
+ declare function fireFromElement(element: Element, options?: FireFromElementOptions): void;
100
+ /**
101
+ * Clear the full-screen canvas and cancel scheduled bursts and streams
102
+ */
103
+ declare function reset(): void;
104
+ /**
105
+ * Remove the full-screen canvas and its listeners; the next fire() creates a new one
106
+ */
107
+ declare function destroy(): void;
108
+ /**
109
+ * Create a konfetti instance that draws into your own canvas
110
+ */
111
+ declare function create(canvas: HTMLCanvasElement, createOptions?: CreateOptions): KonfettiInstance;
112
+ /**
113
+ * Fire a steady stream on the full-screen canvas. Returns a function that stops it.
114
+ */
115
+ declare function continuous(options?: KonfettiOptions, interval?: number): () => void;
116
+ /** Burst of confetti from bottom center shooting up */
117
+ declare const cannon: (options?: KonfettiOptions) => void;
118
+ /** 360 degree burst from center */
119
+ declare const explosion: (options?: KonfettiOptions) => void;
120
+ /** Three quick bursts across the top half */
121
+ declare const fireworks: (options?: KonfettiOptions) => void;
122
+ /** Particles falling from the top */
123
+ declare const rain: (options?: KonfettiOptions) => void;
124
+ /** Gentle falling white flakes */
125
+ declare const snow: (options?: KonfettiOptions) => void;
126
+ /** Bursts from both sides */
127
+ declare const sideCannons: (options?: KonfettiOptions) => void;
128
+ /** Rainbow colors */
129
+ declare const pride: (options?: KonfettiOptions) => void;
130
+
131
+ /**
132
+ * Manages one canvas: the animation loop, particles, physics and rendering.
133
+ * Safe to construct on the server, where every method does nothing.
134
+ */
135
+ declare class Konfetti {
136
+ private readonly pool;
137
+ private readonly renderer;
138
+ private frameId;
139
+ /** Timestamp of the previous frame, or when the loop was scheduled */
140
+ private lastTime;
141
+ private paused;
142
+ private destroyed;
143
+ private readonly resizeWithWindow;
144
+ private readonly timeouts;
145
+ private readonly intervals;
146
+ constructor(canvas?: HTMLCanvasElement, createOptions?: CreateOptions);
147
+ /**
148
+ * Fire one burst. Skipped while the page is hidden, after destroy(), and for
149
+ * visitors who prefer reduced motion (unless disableForReducedMotion is false).
150
+ */
151
+ fire(options?: KonfettiOptions): void;
152
+ /**
153
+ * Fire a built-in preset; options override the preset's own values
154
+ */
155
+ preset(name: PresetName, options?: KonfettiOptions): void;
156
+ /**
157
+ * Fire a small burst every `interval` ms until the returned function is
158
+ * called, or until reset() or destroy()
159
+ */
160
+ continuous(options?: KonfettiOptions, interval?: number): () => void;
161
+ /**
162
+ * Pause the animation; particles stay where they are
163
+ */
164
+ pause(): void;
165
+ /**
166
+ * Resume after pause()
167
+ */
168
+ resume(): void;
169
+ /**
170
+ * Clear all particles, cancel scheduled bursts and streams, stop animating and
171
+ * undo pause()
172
+ */
173
+ reset(): void;
174
+ /**
175
+ * Reset, remove listeners and remove the canvas if this instance created it.
176
+ * The instance ignores every call afterwards.
177
+ */
178
+ destroy(): void;
179
+ private readonly handleResize;
180
+ private readonly handleVisibilityChange;
181
+ /**
182
+ * Start the loop if there is something to animate and nothing prevents it
183
+ */
184
+ private scheduleFrame;
185
+ private cancelFrame;
186
+ private readonly tick;
187
+ }
188
+
189
+ /**
190
+ * Names of all built-in presets
191
+ */
192
+ declare const PRESET_NAMES: readonly PresetName[];
193
+ /**
194
+ * Whether a value names a built-in preset (useful for attribute or prop values)
195
+ */
196
+ declare function isPresetName(value: unknown): value is PresetName;
197
+
198
+ export { type CreateOptions, type FireFromElementOptions, Konfetti, type KonfettiInstance, type KonfettiOptions, type Origin, PRESET_NAMES, type PresetName, type ShapeType, cannon, continuous, create, destroy, explosion, fire, fireFromElement, firePreset, fireworks, isPresetName, originFromElement, pride, rain, reset, sideCannons, snow };
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Shape type for particles
3
+ */
4
+ type ShapeType = 'circle' | 'square';
5
+ /**
6
+ * Origin point (0-1 relative to canvas dimensions)
7
+ */
8
+ interface Origin {
9
+ x: number;
10
+ y: number;
11
+ }
12
+ /**
13
+ * Configuration options for konfetti
14
+ */
15
+ interface KonfettiOptions {
16
+ /** Number of particles to emit (default: 50) */
17
+ particleCount?: number;
18
+ /** Launch angle in degrees, 90 is straight up (default: 90) */
19
+ angle?: number;
20
+ /** Spread angle in degrees (default: 45) */
21
+ spread?: number;
22
+ /** Initial velocity in pixels per frame at 60 fps (default: 45) */
23
+ startVelocity?: number;
24
+ /** Velocity kept per frame at 60 fps, 0-1, lower = faster slowdown (default: 0.9) */
25
+ decay?: number;
26
+ /** Gravity strength (default: 1) */
27
+ gravity?: number;
28
+ /** Horizontal drift (default: 0) */
29
+ drift?: number;
30
+ /** Particle lifetime in frames at 60 fps (default: 200) */
31
+ ticks?: number;
32
+ /**
33
+ * Spawn origin point, 0-1 relative (default: { x: 0.5, y: 0.5 }). An axis you
34
+ * leave out keeps the preset's or default value.
35
+ */
36
+ origin?: Partial<Origin>;
37
+ /** Array of CSS color strings (default: festive colors) */
38
+ colors?: string[];
39
+ /** Particle shapes to use (default: ['circle', 'square']) */
40
+ shapes?: ShapeType[];
41
+ /** Size multiplier (default: 1) */
42
+ scalar?: number;
43
+ /** z-index of the full-screen canvas (default: 100) */
44
+ zIndex?: number;
45
+ /** Disable animation for users who prefer reduced motion (default: true) */
46
+ disableForReducedMotion?: boolean;
47
+ }
48
+ /**
49
+ * Names of the built-in preset effects
50
+ */
51
+ type PresetName = 'cannon' | 'explosion' | 'fireworks' | 'rain' | 'snow' | 'sideCannons' | 'pride';
52
+ /**
53
+ * Options for firing from an element, optionally with a preset
54
+ */
55
+ interface FireFromElementOptions extends KonfettiOptions {
56
+ /** Preset to fire instead of a plain burst */
57
+ preset?: PresetName;
58
+ }
59
+ /**
60
+ * Options for creating a custom konfetti instance
61
+ */
62
+ interface CreateOptions {
63
+ /** Resize the canvas when the window resizes (default: true) */
64
+ resize?: boolean;
65
+ }
66
+
67
+ /**
68
+ * Fire function bound to a canvas, with preset, reset and destroy methods
69
+ */
70
+ interface KonfettiInstance {
71
+ (options?: KonfettiOptions): void;
72
+ /** Fire a built-in preset into this canvas */
73
+ preset: (name: PresetName, options?: KonfettiOptions) => void;
74
+ /** Fire a stream into this canvas; returns a function that stops it */
75
+ continuous: (options?: KonfettiOptions, interval?: number) => () => void;
76
+ /** Clear the canvas and cancel scheduled bursts */
77
+ reset: () => void;
78
+ /** Stop for good and release listeners */
79
+ destroy: () => void;
80
+ }
81
+ /**
82
+ * Fire konfetti on the full-screen canvas
83
+ */
84
+ declare function fire(options?: KonfettiOptions): void;
85
+ /**
86
+ * Fire a built-in preset on the full-screen canvas
87
+ */
88
+ declare function firePreset(name: PresetName, options?: KonfettiOptions): void;
89
+ /**
90
+ * The center of an element, as an origin relative to the viewport
91
+ */
92
+ declare function originFromElement(element: Element): Origin;
93
+ /**
94
+ * Fire from the center of an element, for example the button that was clicked.
95
+ * Single-burst presets (cannon, explosion, pride) start at the element too;
96
+ * screen-wide presets (fireworks, rain, snow, sideCannons) keep their positions.
97
+ * An origin you pass yourself wins, axis by axis.
98
+ */
99
+ declare function fireFromElement(element: Element, options?: FireFromElementOptions): void;
100
+ /**
101
+ * Clear the full-screen canvas and cancel scheduled bursts and streams
102
+ */
103
+ declare function reset(): void;
104
+ /**
105
+ * Remove the full-screen canvas and its listeners; the next fire() creates a new one
106
+ */
107
+ declare function destroy(): void;
108
+ /**
109
+ * Create a konfetti instance that draws into your own canvas
110
+ */
111
+ declare function create(canvas: HTMLCanvasElement, createOptions?: CreateOptions): KonfettiInstance;
112
+ /**
113
+ * Fire a steady stream on the full-screen canvas. Returns a function that stops it.
114
+ */
115
+ declare function continuous(options?: KonfettiOptions, interval?: number): () => void;
116
+ /** Burst of confetti from bottom center shooting up */
117
+ declare const cannon: (options?: KonfettiOptions) => void;
118
+ /** 360 degree burst from center */
119
+ declare const explosion: (options?: KonfettiOptions) => void;
120
+ /** Three quick bursts across the top half */
121
+ declare const fireworks: (options?: KonfettiOptions) => void;
122
+ /** Particles falling from the top */
123
+ declare const rain: (options?: KonfettiOptions) => void;
124
+ /** Gentle falling white flakes */
125
+ declare const snow: (options?: KonfettiOptions) => void;
126
+ /** Bursts from both sides */
127
+ declare const sideCannons: (options?: KonfettiOptions) => void;
128
+ /** Rainbow colors */
129
+ declare const pride: (options?: KonfettiOptions) => void;
130
+
131
+ /**
132
+ * Manages one canvas: the animation loop, particles, physics and rendering.
133
+ * Safe to construct on the server, where every method does nothing.
134
+ */
135
+ declare class Konfetti {
136
+ private readonly pool;
137
+ private readonly renderer;
138
+ private frameId;
139
+ /** Timestamp of the previous frame, or when the loop was scheduled */
140
+ private lastTime;
141
+ private paused;
142
+ private destroyed;
143
+ private readonly resizeWithWindow;
144
+ private readonly timeouts;
145
+ private readonly intervals;
146
+ constructor(canvas?: HTMLCanvasElement, createOptions?: CreateOptions);
147
+ /**
148
+ * Fire one burst. Skipped while the page is hidden, after destroy(), and for
149
+ * visitors who prefer reduced motion (unless disableForReducedMotion is false).
150
+ */
151
+ fire(options?: KonfettiOptions): void;
152
+ /**
153
+ * Fire a built-in preset; options override the preset's own values
154
+ */
155
+ preset(name: PresetName, options?: KonfettiOptions): void;
156
+ /**
157
+ * Fire a small burst every `interval` ms until the returned function is
158
+ * called, or until reset() or destroy()
159
+ */
160
+ continuous(options?: KonfettiOptions, interval?: number): () => void;
161
+ /**
162
+ * Pause the animation; particles stay where they are
163
+ */
164
+ pause(): void;
165
+ /**
166
+ * Resume after pause()
167
+ */
168
+ resume(): void;
169
+ /**
170
+ * Clear all particles, cancel scheduled bursts and streams, stop animating and
171
+ * undo pause()
172
+ */
173
+ reset(): void;
174
+ /**
175
+ * Reset, remove listeners and remove the canvas if this instance created it.
176
+ * The instance ignores every call afterwards.
177
+ */
178
+ destroy(): void;
179
+ private readonly handleResize;
180
+ private readonly handleVisibilityChange;
181
+ /**
182
+ * Start the loop if there is something to animate and nothing prevents it
183
+ */
184
+ private scheduleFrame;
185
+ private cancelFrame;
186
+ private readonly tick;
187
+ }
188
+
189
+ /**
190
+ * Names of all built-in presets
191
+ */
192
+ declare const PRESET_NAMES: readonly PresetName[];
193
+ /**
194
+ * Whether a value names a built-in preset (useful for attribute or prop values)
195
+ */
196
+ declare function isPresetName(value: unknown): value is PresetName;
197
+
198
+ export { type CreateOptions, type FireFromElementOptions, Konfetti, type KonfettiInstance, type KonfettiOptions, type Origin, PRESET_NAMES, type PresetName, type ShapeType, cannon, continuous, create, destroy, explosion, fire, fireFromElement, firePreset, fireworks, isPresetName, originFromElement, pride, rain, reset, sideCannons, snow };