demo · v141

Grapheme Clusters

Pull every grapheme cluster out of a string with getTextClusters({ granularity: "grapheme" }) and animate each one independently. Emoji ZWJ sequences, family stacks, regional indicators, combining marks — the platform tells you exactly where one user-perceived character ends and the next begins.

checking support…

the call

const metrics = ctx.measureText(text);
const clusters = metrics.getTextClusters({ granularity: "grapheme" });
for (const c of clusters) {
  const slice = text.slice(c.begin, c.end);
  ctx.save();
  ctx.translate(originX + c.x + bob(c.begin), originY + c.y);
  ctx.fillText(slice, 0, 0);
  ctx.restore();
}

why this angle

Counting "characters" in a JavaScript string is a trap. "👨‍👩‍👧‍👦".length is 11 because ZWJ sequences are multiple code points; "🇬🇧".length is 4 because regional indicators are pairs of code points; "café".length is 4 or 5 depending on NFC vs NFD. Animation frameworks, typewriter effects, kinetic typography — anyone wanting to move "one character" at a time — had to ship their own grapheme-breaker. getTextClusters hands it back from the platform's text shaper.

see also