StringSplit Module

Granular text choreography for hero headlines, body copy, and captions. StringSplit rebuilds your markup into line, word, and character wrappers, annotates them with deterministic indexes (or controlled randomness), and exposes the data as CSS variables for your animation system.

Activation primer: Add string="split" to every element you want StringSplit to rebuild. Supply string-id="your-id" when you need a stable handle for events, mirrors, or string-copy-from; otherwise StringTune generates one automatically.

HTML Attributes

AttributeApplies toDefaultControlsPractical notes
string-splitSame element"" (no wrappers)Grammar defining which wrappers to build (line, word, char, word-line, char-line, char-word) + indexing rulesTokens are pipe-separated, e.g. word[start] | char[random(0,5)]; brackets accept multiple params via ;
string-split-restore-afterSame elementnot setMilliseconds after which original HTML is restored and -restored class is addedUse for one-off intro animations when content should return to editable state
string-split-originalSame elementinjectedStores pristine HTML captured on first runManaged internally — do not modify manually

Module Snapshot

  • Activation attribute: string="split"
  • Wrappers emitted: optional -s-line, -s-word, -s-char spans (only for groups requested in string-split)
  • CSS variables: indexes for each wrapper (--line-index, --word-index, --char-index, etc.), totals (--word-total, --char-total, --char-global-total), plus alignment variables (--word-start, --char-center, …)
  • Class markers: -before-element / -after-element identify tokens adjacent to inline elements; split-class lets you seed custom classes per token
  • Accessibility: original text stored under aria-label; generated spans marked aria-hidden="true" to avoid double narration
  • Rebuild triggers: re-splits on width resize (mobile height/width rebuild toggles disabled for performance)
  • Cleanup: listeners not required; module restores original markup if destroyed or when string-split-restore-after elapses

Basic Usage

import StringTune, { StringSplit } from '@fiddle-digital/string-tune';

const stringTune = StringTune.getInstance();
stringTune.use(StringSplit);
stringTune.start(60);
<h1 string="split" string-id="hero-heading" string-split="line[center];word[start]|charWord[start];charWord[end]" class="hero-heading">
  Lift stories off the baseline
</h1>
.hero-heading {
  --char-delay-step: 12ms;
}

.hero-heading .-s-line {
  display: block;
  transform-origin: 50% 50%;
  transform: rotate(calc(var(--line-center, 0) * 0.5deg));
}

.hero-heading .-s-word {
  display: inline-block;
  transition-delay: calc(var(--word-start, 0) * 40ms);
}

.hero-heading .-s-char {
  display: inline-block;
  transition-delay: calc(var(--charWord-start, 0) * var(--char-delay-step));
  transform: translateY(calc((1 - var(--charWord-end, 0)) * 1.2em));
  opacity: calc(var(--charWord-end, 0));
}

Split Grammar Essentials

  • Tokens are pipe-separated: token[paramA;paramB] | another-token[...].
  • Hyphenated names in HTML (word-line) map to camelCase internally (wordLine).
  • Alignment params accept start, end, center, random, and random(min,max); abs is parsed for future use.
  • Each token adds or augments wrappers, producing CSS variables documented below.
  • Random alignments recompute on each rebuild; persist the DOM if you need deterministic sequences.

string-split Token Reference

Token snippetWrapper(s) producedIndex scopeSupported paramsCSS variables emittedNotes
line[...]Generates span.-s-line per text lineAll lines inside the elementstart, end, center, random(min,max), abs--line-index, --line-*, --word-totalAdds optional <br> for gaps; enables line-level motion
word[...]Generates span.-s-word per wordEvery word in the elementSame as above--word-index, --word-*, --char-totalRequired if you want per-word transforms or word-line metrics
word-line[...]Reuses -s-word wrappersWords within the current lineSame as above--wordLine-*Adds line-scoped indexes so words can animate relative to their line
char[...]Generates span.-s-char per characterAll characters across the elementSame as above--char-index, --char-*, --char-global-total (on root)Enables per-character animation; respects kerning adjustments
char-word[...]Reuses -s-char wrappersCharacters within the current wordSame as above--charWord-*Great for stagger effects that restart each word
char-line[...]Reuses -s-char wrappersCharacters within the current lineSame as above--charLine-*Useful for wave effects that sweep line by line

Tip: wrap inline segments with <split-class class="accent">...</split-class> to push custom classes onto the generated wrappers.

Generated CSS Variables

StringSplit writes variables directly on the wrappers it creates. Use them to compute delays, offsets, and transforms without extra JavaScript. Values are always numbers (integers for indexes, decimals for averages) and are only emitted when the corresponding token is present.

Line-level (span.-s-line)

VariableMeaningExample value
--line-indexZero-based position of the line within the element0 for the first line
--line-start, --line-center, --line-endAlignment counters based on the option you declared2 meaning “two steps from the chosen anchor”
--line-randomRandom integer inside the requested range4 when line[random(0,5)] is active
--word-totalNumber of words in this line5 for a five-word line

Word-level (span.-s-word)

VariableMeaningExample value
--word-indexWord order across the entire block7 for the eighth word
--word-start, --word-center, --word-end, --word-randomAlignment counters driven by the word[...] token1 → one step from the anchor
--wordLine-start, --wordLine-center, --wordLine-end, --wordLine-randomLine-scoped alignment from word-line[...]0 meaning “first word in its line”
--char-totalCharacter count inside this word (excluding spaces)6 for “String”

Character-level (span.-s-char)

VariableMeaningExample value
--char-indexGlobal character order across the element23 for the 24th glyph
--char-start, --char-center, --char-end, --char-randomAlignment counters from the char[...] token3 meaning “third from the chosen edge”
--charWord-start, --charWord-center, --charWord-end, --charWord-randomWord-scoped alignment from char-word[...]0 for the first letter in its word
--charLine-start, --charLine-center, --charLine-end, --charLine-randomLine-scoped alignment from char-line[...]5 for the sixth glyph in the line
--char-global-total (set on the root element)Total number of characters across all lines74 for a long paragraph

Variables appear only when their corresponding token is declared, keeping unused CSS clean.

Output Structure & Styling Hooks

  • DOM rebuild: original HTML is cloned into a DocumentFragment, measured, and rebuilt into the output fragment. Inline elements (e.g., <em>, <svg>) are cloned wholesale and reinserted as words so your semantic markup survives.
  • Whitespace management: the engine inserts non-breaking spaces (\u00a0) where needed so the visual spacing mirrors your source copy. <br> tokens force line breaks in the rebuilt structure.
  • Kerning preservation: character wrappers compute pixel-perfect widths using a hidden canvas (FontMetrics) and apply precise margin-right values so browsers with loose kerning still align flawlessly.
  • Special classes: wrapping text with <split-class class="accent">…</split-class> pushes accent onto either the entire word wrapper (if all chars inherit it) or individual -s-char nodes, letting you flag tokens for bespoke animation.
  • Element adjacency: spans bordering inline elements gain -before-element or -after-element so you can smooth transitions between text and icons.
  • Data mirrors: every wrapper carries data-split-content with its textual payload—a handy escape hatch for debugging or fallbacks.

Alignment Strategies Explained

  • start / end / center: produce deterministic integers beginning at 0. start counts forward, end counts backwards, and center returns the distance to the mid-point (useful for symmetric easing).
  • random(min,max): produces an integer inside the provided inclusive range. Omit parameters to default to the full span (0length - 1).
  • word-line / char-line / char-word: scope the counter to the enclosing line or word. Example: combine word[start] with charWord[start] to orchestrate wave animations that reset for each word.

Restoring & Re-running

  • Caching: the untouched HTML is stored in string-split-original; repeated connections reuse the cache to prevent progressive degradation.
  • Timed restore: setting string-split-restore-after="2500" restores the raw HTML after 2.5 s, adds -restored, and keeps aria attributes intact—ideal for animating in then letting editors retain editability.
  • Manual refresh: call stringTune.onResize(true) after changing the string-split attribute to rebuild the structure.

Accessibility & Performance Notes

  • Screen readers read aria-label (the original string) while generated spans remain hidden, so you get visuals without duplicating narration.
  • Width-only rebuilds prevent choppy behavior on mobile orientation changes; if you inject fonts dynamically, call stringTune.onResize(true) once the family is ready so kerning recalculates.
  • Random alignments recompute on each rebuild; persist the generated structure if you need fixed ordering (e.g., snapshot the DOM before hydration completes).

Event Signals

StringSplit does not emit custom bus events. Hook into object:connected:<id> from the core engine if you need to react once splitting completes.


StringSplit turns textual content into a choreography-ready data structure—annotated spans, predictable indexes, and kerning-aware wrappers—so you can script expressive typography without hand-crafting DOM for every headline.