Two takes on the same measuring rig. The reference bar gives every word a colour tile, but the tile is not the line box: canvas measureText's actualBoundingBoxAscent/Descent gives each character its true ink box (getExtentOfChar would return an identical em box for every glyph), so a rect hugs the skyline of the letters above it while x positions come from cumulative substring widths to keep kerning honest. Tiles fly in 130 ms apart over 760 ms once the bar is in view, then idle-shuffle swatches every 1.3-3.2 s with a 520 ms colour lerp and re-roll on hover. The lower bar fuses that with the particle spoiler: the text lives inside the SVG beside its rects, hidden under a cloud sampled from its own coverage, and a tap drives one shared screen-space radius through a per-word SVG mask so the iris opens across every tile at once.
Source
"use client";
import { useState } from "react";
import DesignTiles from "@/components/DesignTiles";
import TileSpoiler from "@/components/TileSpoiler";
import ScrambleLink from "../ScrambleLink";
/* The /tiles evaluation route, re-homed in the lab — same two components, same
pairing. Top: the reference bar, one colour tile per word, each tile's box
measured from the glyphs it actually sits under. Bottom: the same tiles fused
with the particle spoiler, so the phrase arrives hidden and a tap opens the
iris. `run` remounts both, because each only plays its entrance once. */
const WORDS = ["design", "is", "how", "it", "works"];
const label: React.CSSProperties = {
fontSize: 10,
letterSpacing: "0.14em",
textTransform: "uppercase",
color: "var(--faint)",
fontFamily: "var(--flux)",
fontVariationSettings: '"wght" 400, "SRIF" 100',
};
export default function DesignTilesDemo() {
const [run, setRun] = useState(0);
return (
<div
className="fixed inset-0 flex flex-col items-center justify-center overflow-hidden px-6 select-none"
style={{ background: "var(--paper)" }}
>
<span style={label}>reference · variable bounding box per character</span>
<DesignTiles
key={`tiles-${run}`}
words={WORDS}
style={{
width: "min(88%, 720px)",
minHeight: "clamp(3.5rem, 11vh, 6.5rem)",
marginTop: 14,
}}
/>
<span style={{ ...label, marginTop: 34 }}>
fusion · same tiles + particle blur (tap to open the iris)
</span>
<TileSpoiler
key={`spoiler-${run}`}
text={WORDS.join(" ")}
style={{ fontSize: "clamp(1.3rem, 3.1vw, 2.5rem)", marginTop: 16 }}
/>
<button
onClick={() => setRun((n) => n + 1)}
className="mt-10 text-[11px] tracking-[0.1em] uppercase transition-colors"
style={{
color: "var(--faint)",
fontFamily: "var(--flux)",
fontVariationSettings: '"wght" 400, "SRIF" 100',
}}
>
replay
</button>
<div className="fixed bottom-6 left-6 z-10">
<ScrambleLink
from="DESIGN TILES"
to="← LAB"
href="/lab"
className="text-[11px] tracking-[0.1em] text-foreground/30 uppercase hover:text-foreground/60 transition-colors"
style={{ fontVariationSettings: "'wght' 400, 'SRIF' 100" }}
/>
</div>
</div>
);
}