claude2video
blog
← Back

How to Add Confetti to a Claude Design Animation

Tomas P · Updated on May 28, 2026

How to Add Confetti to a Claude Design Animation

Confetti is the cheapest way to mark a moment in an animation. A pricing reveal, a "you won", a launch beat, an end-of-pitch flourish. Below is a short clip built in Claude Design and exported with Claude2Video, followed by the exact prompt that makes it loop-safe and frame-perfect.

Why It Needs a Prompt

The naive "add confetti" prompt almost always produces CSS-keyframe confetti that drifts out of sync with the rest of the scene, or per-frame randomness that makes pieces teleport. Neither survives a frame-by-frame export.

The fix is to drive every piece from the stage's useTime() with deterministic physics and a seeded PRNG. The prompt below spells that out, plus the small details (curated palettes, integer time harmonics, sensible piece counts) that separate "confetti" from "particles falling out of nowhere".

The Prompt

Paste this into Claude Design as an addendum to your animation prompt - or as a standalone request when you want a pure confetti scene. It is written as a spec, so Claude Design treats it as a contract rather than a suggestion.

# Adding confetti to an animation

Confetti is many absolutely-positioned `<div>`s, each driven every frame from the
stage's `useTime()`. Never use CSS keyframes — they don't sync with the timeline.

## Per-piece data (pre-compute ONCE with `useMemo` + seeded PRNG)
- `vx, vy`           initial velocity (px/s)
- `w, h`             size — rects: 8–18 × 12–26; streamers: 4–5 × 28–50
- `color`            from a curated 5–8-hue palette (NOT random HSL)
- `shape`            mostly `rect` (1px radius); ~15% `circle`; ~5–10% `streamer` (fully rounded)
- `rotSpeed`         ±(400–1500) deg/s
- `tumbleSpeed`      4–10 rad/s
- `tumblePhase`      0..2π
- `delay`            0–0.1s — stagger so a burst doesn't fire in a single frame

Use mulberry32 (seeded) for randomness. Random per-frame = pieces teleport.

## Physics every frame (`ts` = seconds since the piece spawned)
```
drag = 0.5                                                   // 0.4–0.6
dx = (vx / drag) * (1 - exp(-ts * drag))
dy = (vy / drag) * (1 - exp(-ts * drag)) + 0.5 * 1400 * ts*ts // gravity ≈ 1400 px/s²
rot = rotSpeed * ts                                          // degrees
flipScaleY = cos(ts * tumbleSpeed + tumblePhase)             // -1..1, 3D edge-on flip illusion
```
Apply as:
```
transform: translate(${dx}px, ${dy}px) rotate(${rot}deg) scaleY(${flipScaleY})
transformOrigin: center   // each piece rotates around ITSELF, not the spawn point
willChange: transform, opacity
```

## Fade
- Hold `opacity: 1` for the first ~75% of life, then `easeInQuad` to 0.
- For sustained-spawn (rain), add a 0.3s fade-in so spawns don't pop.

## Three motion patterns
| Pattern  | Origin                | Angle                          | Speed       | Count        |
|----------|-----------------------|--------------------------------|-------------|--------------|
| Burst    | shared point          | upward hemisphere (-160°..-20°)| 650–1400    | 80–100       |
| Rain     | random X, Y above top | straight down + sin sway       | 130–280     | 100–150      |
| Cannon   | screen edge / corner  | tight ±15° spread inward       | 1200–2000   | ~50/cannon   |

For cannons: mix in foil streamers via
`background: linear-gradient(135deg, ${color} 0%, #fff6cc 22%, ${color} 50%, #ffe590 72%, ${color} 100%)`.
Add a one-frame radial flash at burst/cannon trigger for impact.

## Loop-safety & containment
- Whole scene must derive from `useTime()`. No internal mutable state.
- Trigger pattern: `if (t < TRIGGER) return null; const localT = t - TRIGGER;`
- To confine confetti to a window in a longer scene, accept a `trigger` (burst /
  cannon) or `startTime` (rain) prop so the parent can re-time the effect.
- Return `null` for pieces past their lifetime — don't render zombies.

## Counts & perf
- React handles ~150 pieces at 60fps; past that, drops frames.
- A flat 1px `box-shadow: 0 1px 2px rgba(0,0,0,0.25)` is fine. Blurred shadows on
  100+ pieces will tank perf.
- No `filter: blur()` on individual pieces.

## Palettes (curate, never randomize freely)
```
party:      ['#FF2D55','#FF9500','#FFCC00','#34C759','#00C7BE','#5856D6','#AF52DE','#FF3B30']
pastel:     ['#FFB3C7','#FFE3B3','#B3FFD9','#B3D9FF','#D9B3FF','#FFC9B3']
goldFoil:   ['#FFD76E','#F6BC3B','#C98D18','#FFE8A0','#B88119']
silverFoil: ['#F2F4F8','#C5CCD6','#A6B1C0','#FFFFFF','#8E99AA']
mono:       ['#FFFFFF','#E8E8E8','#BDBDBD','#7D7D7D']
```

## Specialized variant: clipped fragments (object exploding)
To make an existing object (a card, a paper, a logo) shatter INTO its own
fragments rather than generic confetti:
1. Build N polygon `clip-path`s tiling the object's bounding box (jittered grid).
2. For each fragment, render a full-size COPY of the object inside a wrapper
   with that `clip-path` applied — so each piece shows its slice of the original.
3. Compute the **centroid** of each polygon (avg of vertices) and use it as
   `transformOrigin` (in %). This makes each fragment rotate around itself
   instead of swinging around the object's center.

See Each Pattern

Four short clips, one per pattern in the prompt above. Each one is what you get if you ask Claude Design for that variant on its own.

Burst - a single shared origin, upward hemisphere, 80-100 pieces. The default for "we did it" moments.

Rain - random spawn above the top edge, straight down with a small sin sway. Reads as ambient and works under a sustained beat.

Side cannons - two screen-edge origins firing inward in a tight cone, with foil streamers mixed in. The most "stadium" of the three.

Clipped fragments - the specialized variant from the bottom of the prompt. An existing object shatters into its own slices rather than being covered by generic confetti.

How to Use It

Three ways, depending on what you are building:

  1. Standalone confetti scene. Paste the prompt and ask for "a 6-second burst scene at 1920x1080, party palette, single burst at t=0.4". Useful for a stinger you can drop into any video editor later.
  2. Add to an existing animation. Paste the prompt after your scene prompt, then add: "trigger a burst at the end of beat 3 using the party palette". Claude Design will wire the trigger to your existing timeline.
  3. Object explosion. When you want a card or logo to shatter rather than be covered, point at the existing component and ask for "clipped-fragment confetti of <LogoCard />, gold foil palette, trigger at t=4.2". The clipped-fragments variant in the prompt above is exactly this case.

Adjusting the Look

The prompt is a contract on the physics and structure, not the look. A few things you can change without breaking the loop math:

  • Swap the palette. Replace one of the curated palettes with your brand colors. Keep it to 5-8 hues so the eye still reads "confetti" and not "noise".
  • Tune piece count. Drop to 40-60 for a small flourish, push 120-150 for a stadium burst. Above 150, frames will drop during capture.
  • Change the pattern. Burst for a single moment, rain for an ambient celebration loop, cannons for big launches. Mixing two patterns (rain underneath, burst on top) reads as the most cinematic.

Frequently Asked Questions

Why not use a library like canvas-confetti? Claude Design renders React to the DOM and drives time through useTime() on its own stage. canvas-confetti runs on its own internal requestAnimationFrame clock, so its frames will not line up with the Claude2Video exporter's frame-by-frame capture, and the result usually shows torn or skipped pieces in the final MP4. Driving plain <div>s from useTime() is the only way to get a clean export.

Will the confetti slow down the video export? Up to about 150 pieces, no. The capture is paced by the exporter, not real-time, so even a heavy burst renders cleanly - it just takes a few extra seconds of capture time. Past 150 pieces the React reconciler starts dropping frames during capture, which shows up as visible stutter in the MP4.

Can I make the confetti react to the audio beat? Not directly - Claude Design has no audio API, and the voiceover and music are mixed in at export time, not at design time. The workaround is to plan your beats during the scripting step and place the burst triggers at the same timecodes. If you generate the voiceover with Claude2Video's built-in TTS, the timing is predictable enough to line up by hand. For a longer walkthrough of that workflow, see the animated product demo guide.