Constrained damped-spring char stagger with decaying chromatic split.
<!doctype html>
<!-- Example: split-char-bounce — viewport-safe spring stagger · chromatic decay · ambient pulse -->
<html data-duration="5" 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: #f4f1ea; color: var(--ink); height: 100vh;
display: grid; place-items: center; font-family: ui-sans-serif, system-ui;
overflow: hidden; position: relative; }
.glow { position: absolute; left: 50%; top: 50%; width: 90vw; height: 60vh;
transform: translate(-50%, -50%);
background: radial-gradient(ellipse, rgba(255,59,31,.10), transparent 60%);
pointer-events: none; will-change: transform, opacity; }
.rule { position: absolute; left: 8vw; right: 8vw; height: 1px;
background: rgba(10,10,10,.18); pointer-events: none; }
.rule.r1 { top: 22vh; } .rule.r2 { bottom: 22vh; }
.stage { position: relative; max-width: 80vw; padding: 0 4vw;
display: grid; place-items: center; }
.bounds { position: relative; overflow: hidden; padding: 1.5em 0; line-height: 1; }
.t { font-size: clamp(64px, 12vw, 188px); font-weight: 800; letter-spacing: -0.05em;
display: flex; gap: 2px; justify-content: center; white-space: nowrap;
line-height: 1; }
.t span.ch { display: inline-block; transform-origin: bottom; will-change: transform, opacity;
position: relative; }
.t .accent { color: var(--signal); }
.gh { position: absolute; inset: 0; pointer-events: none;
font: inherit; letter-spacing: inherit; }
.gh.r { color: rgba(255,59,31,.6); mix-blend-mode: multiply; }
.gh.b { color: rgba(43,102,255,.55); mix-blend-mode: multiply; }
.cap { font-family: ui-monospace, monospace; font-size: 12px; letter-spacing: .25em;
text-transform: uppercase; color: var(--mute); text-align: center;
margin-top: 36px; display: flex; align-items: center; justify-content: center; gap: 14px; }
.cap .pip { width: 24px; height: 1px; background: var(--mute); display: inline-block; }
.tag { position: absolute; top: 36px; left: 56px;
font-family: ui-monospace, monospace; font-size: 11px; letter-spacing: .26em;
text-transform: uppercase; color: var(--mute);
display: inline-flex; align-items: center; gap: 8px; }
.tag::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--signal); }
</style></head><body>
<div class="glow" id="gl"></div>
<div class="rule r1"></div>
<div class="rule r2"></div>
<div class="tag">spring · stagger · chromatic decay</div>
<div class="stage">
<div class="bounds">
<div class="t" id="t"></div>
</div>
<div class="cap"><span class="pip"></span>k = 9 · damping 0.78 · split → 0 on settle<span class="pip"></span></div>
</div>
<script>
var WORD = 'HYPERFRAMES';
var root = document.getElementById('t');
var gl = document.getElementById('gl');
var chars = WORD.split('').map(function(c, i) {
var el = document.createElement('span');
el.className = 'ch' + (i >= 5 ? ' accent' : '');
el.textContent = c;
var r = document.createElement('span');
r.className = 'gh r'; r.textContent = c;
var b = document.createElement('span');
b.className = 'gh b'; b.textContent = c;
el.appendChild(r); el.appendChild(b);
root.appendChild(el);
return { el: el, r: r, b: b };
});
var t = 0;
var reduced = matchMedia('(prefers-reduced-motion: reduce)').matches;
// Damped spring evaluated as a closed form over a normalized [0..1] phase.
function spring(u) {
if (u <= 0) return 0;
if (u >= 1) return 1;
var damp = Math.exp(-3.4 * u);
return 1 - damp * Math.cos(u * Math.PI * 2.1);
}
function render() {
var tt = reduced ? 1.6 : t;
chars.forEach(function(o, i) {
var start = i * 0.055;
var u = Math.max(0, Math.min(1, (tt - start) / 0.85));
var s = spring(u);
// Constrained drop: max 42px lift, fully inside the .bounds wrapper.
var y = (1 - s) * 42;
var sx = 0.92 + s * 0.08;
var rot = (1 - u) * (i % 2 === 0 ? -3 : 3);
o.el.style.transform =
'translateY(' + y.toFixed(1) + 'px) scale(' + sx.toFixed(3) + ') rotate(' + rot.toFixed(2) + 'deg)';
o.el.style.opacity = String(Math.min(1, u * 1.3));
// Chromatic split peaks at u=1 (the spring "ring") and decays after.
var ring = Math.max(0, 1 - Math.abs(u - 1) * 2.4);
var split = ring * 8;
o.r.style.transform = 'translateX(' + (-split).toFixed(1) + 'px)';
o.b.style.transform = 'translateX(' + split.toFixed(1) + 'px)';
o.r.style.opacity = String(Math.min(1, ring * 0.85));
o.b.style.opacity = String(Math.min(1, ring * 0.85));
});
// Ambient glow breathes with the spring's mean energy.
var br = 0.92 + 0.08 * Math.sin(tt * 1.4);
gl.style.transform = 'translate(-50%, -50%) scale(' + br.toFixed(3) + ')';
gl.style.opacity = String(0.7 + 0.3 * Math.sin(tt * 0.9));
}
addEventListener('hf-seek', function(e) { t = e.detail.time; render(); });
render();
</script>
</body></html>Editorial line-by-line clip reveal with monospace ticker and accent flash.
SVG path interpolation between topology-matched glyph shapes.
Ink-bleed displacement with hand-drawn underline path-draw.