200-particle confetti with gravity and rotation.
Edit these placeholders inline or pass --var NAME=value to hyperframes render.
| Variable | Type | Default | Range |
|---|---|---|---|
{{$MESSAGE}}Headline | text | Shipped. | — |
{{$COUNT}}Particle count | number | 200 | 20 → 600 step 10 |
{{$GRAVITY}}Gravity | number | 800 | 100 → 2000 step 50 |
<!doctype html>
<html data-duration="6" data-aspect="16:9"><head><style>
:root {
--cream:#f6f5f1; --cream-2:#efece4; --ink:#0a0a0a; --mute:#6b6862;
--line:#e3dfd3; --signal:#ff3b1f; --signal-2:#ff6a4a; --frame:#ffb800;
--green:#1f8a5b; --blue:#2b66ff;
}
* { box-sizing: border-box; }
body { margin:0; }
body { background: var(--cream); height: 100vh; overflow: hidden; position: relative;
display: grid; place-items: center; font-family: ui-sans-serif, system-ui; }
.msg { font-size: 88px; font-weight: 800; letter-spacing: -.04em; color: var(--ink); z-index: 0; }
canvas { position: absolute; inset: 0; pointer-events: none; }
</style></head><body>
<div class="msg">🎉 {{$MESSAGE}}</div>
<canvas id="c"></canvas>
<script>
var c = document.getElementById('c');
var ctx = c.getContext('2d');
function fit(){ c.width = innerWidth; c.height = innerHeight; }
fit(); addEventListener('resize', fit);
var COLORS = ['#ff3b1f','#ffb800','#1f8a5b','#2b66ff','#ff6a4a'];
var N = {{$COUNT}};
var G = {{$GRAVITY}};
var parts = [];
var seed = 1;
function rand(){ seed = (seed * 9301 + 49297) % 233280; return seed / 233280; }
for (var i = 0; i < N; i++){
parts.push({
x: c.width/2, y: c.height/2,
vx: (rand()-0.5) * 900, vy: (rand()-0.9) * 700,
rot: rand() * Math.PI * 2, vr: (rand()-0.5) * 12,
size: 8 + rand() * 8,
color: COLORS[Math.floor(rand() * COLORS.length)],
});
}
function render(t){
ctx.clearRect(0,0,c.width,c.height);
parts.forEach(function(p){
var x = p.x + p.vx * t;
var y = p.y + p.vy * t + 0.5 * G * t * t;
var rot = p.rot + p.vr * t;
ctx.save(); ctx.translate(x,y); ctx.rotate(rot);
ctx.fillStyle = p.color;
ctx.fillRect(-p.size/2, -p.size/4, p.size, p.size/2);
ctx.restore();
});
}
addEventListener('hf-seek', function(e){ render(e.detail.time); });
render(0);
</script>
</body></html>