# FireworksHdr

> GPU fireworks background with a deterministic, DOM-free physics core (rockets, peony/willow/ring/glyph shells, sparks, embers, smoke) rendered by a WebGPU engine into a wide-gamut, extended-tone-mapping canvas so bursts and comet trails burn brighter than SDR white on HDR displays, degrading silently through a WebGL2 fallback and a soft-knee SDR path everywhere else.

- Package: `fancy-ui-svelte` (Svelte 5 + Tailwind CSS v4)
- Category: Effects
- Tags: hdr, webgpu, particles, fireworks, background
- Docs: https://fancy-ui.rama.app/docs/components/fireworks-hdr
- Source: https://github.com/RamaHerbin/fancy-ui/tree/main/src/lib/fancy-ui/fireworks-hdr

## Import

```svelte
<script lang="ts">
  import { FireworksHdr } from 'fancy-ui-svelte';
</script>
```

Setup (once per project): `npm install fancy-ui-svelte`, then add `@import "fancy-ui-svelte/tailwind.css";` after `@import "tailwindcss";` in your main CSS file. Full guide: https://fancy-ui.rama.app/llms.txt

React: `import { FireworksHdr } from 'fancy-ui-react';` (same prop names; `class` becomes `className`, snippets become `ReactNode`).

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `palette` | `string[]` | `["#ff2fd6","#a142ff","#3d5bff","#42cfff"]` | Brand hues (hex); order-independent, sorted cool→warm for the shell sweep |
| `hdr` | `boolean` | `true` | Opt into the GPU engine (WebGPU HDR first, then a WebGL2 fallback); when false, no engine boots |
| `exposure` | `number` | `2.2` | Display exposure multiplier, clamped to [1, 4] |
| `ambient` | `boolean` | `true` | Run the ambient auto-scheduler (Poisson-timed background shells) |
| `ambientIntensity` | `number` | `0.35` | Ambient energy [0,1] — scales shell size |
| `interactive` | `boolean` | `true` | Launch a shell toward the pointer on pointerdown |
| `quality` | `"auto" \| "high" \| "mid" \| "low"` | `"auto"` | Particle budget; auto picks from the render level and device pixel ratio |
| `respectReducedMotion` | `boolean` | `true` | Force ambient off under prefers-reduced-motion (explicit launches still work) |
| `class` | `string` | `""` | Extra classes on the canvas wrapper |
| `ambientShells` | `ShellKind[]` | — | Restrict the ambient scheduler to these shells, picked uniformly — including the pattern shells 'heart' and 'star'; defaults to a weighted peony/willow/ring mix ('glyph' and 'shape' are ignored, they need caller-supplied points) |
| `onReady` | `(handle: FireworksHandle) => void` | — | Fired when the engine is live with an imperative handle, and again with a fresh handle after a recovered GPU context loss; never fired when no GPU renderer comes up |
| `onLost` | `() => void` | — | Fired once when a GPU context loss could not be recovered; the component has torn itself down and any handle it gave out is inert |

## Examples

### Basic Usage

Ambient shells run on their own; tap the sky or use the handle to launch one. Brightest on an HDR display in a WebGPU browser, and safe (soft-knee SDR) everywhere else.

```svelte
<script lang="ts">
	import { FireworksHdr, type FireworksHandle } from "fancy-ui-svelte";

	let handle = $state<FireworksHandle | null>(null);

	function launch() {
		// Fire a shell toward a random point in the upper half of the frame.
		handle?.launch({ apex: { x: 0.3 + Math.random() * 0.4, y: 0.24 + Math.random() * 0.2 } });
	}
</script>

<div class="relative h-80 w-full overflow-hidden rounded-lg border bg-black">
	<FireworksHdr onReady={(h) => (handle = h)} />
	<div class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3">
		<p class="text-sm text-white/60 select-none">Tap the sky, or send one up</p>
		<button
			type="button"
			onclick={launch}
			class="pointer-events-auto rounded-full border border-white/20 bg-white/10 px-4 py-1.5 text-sm font-medium text-white backdrop-blur transition hover:bg-white/20"
		>
			Launch a shell
		</button>
	</div>
</div>
```

### Pattern shells

Shells that break into a figure: the built-in heart and star, or any closed outline you pass as points. The burst is cut from the figure, so it draws itself in the sky and then droops.

```svelte
<script lang="ts">
	import { FireworksHdr, type FireworksHandle, type ShellKind } from "fancy-ui-svelte";

	let handle = $state<FireworksHandle | null>(null);

	// Any closed figure works: points are y-up around the origin, scale is free.
	// This one is a lightning bolt drawn by hand.
	const BOLT = [
		{ x: 0.1, y: 1 },
		{ x: -0.55, y: 0.05 },
		{ x: -0.1, y: 0.05 },
		{ x: -0.3, y: -1 },
		{ x: 0.5, y: 0.1 },
		{ x: 0.05, y: 0.1 },
	];

	function fire(shell: ShellKind, shapePoints?: { x: number; y: number }[]) {
		handle?.launch({
			apex: { x: 0.3 + Math.random() * 0.4, y: 0.3 },
			shell,
			shapePoints,
		});
	}
</script>

<div class="relative h-80 w-full overflow-hidden rounded-lg border bg-black">
	<FireworksHdr ambientShells={["heart", "star", "peony"]} onReady={(h) => (handle = h)} />
	<div class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3">
		<p class="text-sm text-white/60 select-none">Pattern shells</p>
		<div class="pointer-events-auto flex gap-2">
			{#each [["heart", "Heart"], ["star", "Star"]] as const as [kind, label] (kind)}
				<button
					type="button"
					onclick={() => fire(kind)}
					class="rounded-full border border-white/20 bg-white/10 px-4 py-1.5 text-sm font-medium text-white backdrop-blur transition hover:bg-white/20"
				>
					{label}
				</button>
			{/each}
			<button
				type="button"
				onclick={() => fire("shape", BOLT)}
				class="rounded-full border border-white/20 bg-white/10 px-4 py-1.5 text-sm font-medium text-white backdrop-blur transition hover:bg-white/20"
			>
				Custom
			</button>
		</div>
	</div>
</div>
```
