DecodeText
Text resolving out of a run of cipher glyphs, one character at a time, without the line moving while it does.
Options
-
glyphsABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#%&*+-=?/<>[]{} -
The characters it cycles through before each letter lands. Keep them the same case and roughly the same weight as the text, or the line flickers between dark and light as it runs. Katakana is the one everybody reaches for and the one that dates the effect hardest.
-
orderforward -
forward · reverse · centre · random
The order the characters land in. Forward reads as something being typed or decoded. Random reads as something settling, and is the better one for a paragraph, where a left to right sweep takes long enough to watch.
-
stagger45 -
0 to 300 ms, good: 20 to 90
Milliseconds between one character landing and the next. This is the control that sets the length of the whole run, because the last character lands at hold plus stagger times the number of characters. Short text can afford to be slow; a paragraph at 45ms is a run most of a minute long.
-
hold160 -
0 to 2000 ms, good: 0 to 400
Milliseconds of cipher before the first character lands. A short hold is what makes it read as text arriving from somewhere rather than as text already there and merely untidy.
-
rate18 -
2 to 60 per second, good: 12 to 24
Glyph changes per second, and a cadence rather than a frame rate: everything still running changes on the same tick, which is what makes the line read as one mechanism rather than a row of independent ones. Past about 30 the characters stop being readable and the whole thing greys out.
-
dim0.45 -
0 to 1
How much paler an unlanded glyph is than the settled text. The reason to have it at all is that it separates the two states by more than the letters themselves do, so the text reads as arriving rather than as correcting itself.
-
steadytrue -
true · false
Hold each character in a box the width of the letter it will become. On for anything set in a proportional face, where an I becoming a W is enough to shift the rest of the line. Off for monospace, where the boxes are all the same width and measuring them is work for nothing.
-
seed7 -
0 to 9999
Seed for the glyphs and for the random order. The same seed always gives the same run, so a recorded video and a live page match character for character.
-
reducedMotionTime999 -
0 to 9999 s
The single frame shown when the user prefers reduced motion. For a one-shot reveal this should be a time after the run has finished, so the text simply appears.
What it needs
- Category
- Type, an effect
- Dependencies
- None at all
- Browser
- No WebGL
- Frame budget
- ~0.4 ms · 0 context
- Pinned to
- v0.13.0
- No canvas and no WebGL. It splits the text already in the element and swaps the characters that have not landed yet
- Pure in t. The usual way to write this is Math.random on a timer, which cannot be seeked, cannot be recorded, and shows something different every time anybody looks at it. The glyph at each position is a hash of the position, the seed and the frame number, so the same t always gives the same frame
- The glyphs change on their own cadence rather than once per frame. A per-frame swap is a grey blur at 120Hz and a legible stream at 30, which means the effect would look like a different effect depending on the monitor
- Each character is held in a box the width of the letter it will become, so a line decoding in the middle of a page does not push the page about. Turn `steady` off for monospace, where every box is the same width anyway
- Whitespace and punctuation are left alone. They carry the shape of the sentence, and scrambling the spaces turns text being decoded into a block of noise. It is also what keeps the word wrapping intact
- The original string stays in the accessibility tree as one label, so a screen reader reads the sentence rather than a live stream of junk
- destroy() puts the original text back, leaving the element as it was found
- One text swap per unlanded character per cadence tick, and nothing at all once a character has landed. The comparison before each write matters: setting textContent every frame on a paragraph is a layout invalidation per character per frame for a string that is usually the one already there
- Widths are measured once, again when the webfont arrives, and again on resize. Never per frame