Skip to content

Latest commit

Β 

History

18 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

retro-text-effects.js

English Β· Deutsch


A browser port of TerminalTextEffects (TTE), the Python terminal-effects library - rebuilt in dependency-free vanilla JavaScript and shipped as a single file you can drop into any page.

Live demo - every effect runs right in your browser.

The effects come in five groups:

  • Text effects run on a plain <pre> block by rewriting its text content - no canvas, the text stays selectable, box-drawing characters stay aligned, and the colour is inherited from your element (perfect for an already-green console).
  • Canvas effects lay a temporary canvas over the element for free 2D character motion (fireworks, black hole, rain, ...), then fade it out and reveal the untouched text below.
  • Style effects (crt, colorshift, highlight, gradient) recolour or light the element in place without ever touching the text, so they layer cleanly over an already-visible console.
  • Input effects (placeholder) live inside a form field: they type its placeholder line by line and rewrite nothing else - not the value, not the styling, not the markup.
  • Art effects (aura) are the exception: they do not read text from the page, they generate it. Any Unicode glyph becomes an ASCII figure wrapped in a moving ring of characters, and the animation keeps running until you cancel it.

Quick start

<pre id="log">=== System ready ===</pre>

<script src="retro-text-effects.min.js"></script>
<script>
  RetroTextEffects.decrypt('#log');
</script>

That is the whole integration: one script tag exposes window.RetroTextEffects, then call an effect with an element or a CSS selector.

One thing about the font. The scramble effects cycle through block and shade glyphs (β–‘β–’β–“β–ˆ), and matrix/matrix2 add katakana. If the font of the target element does not contain them, the browser pulls them from a fallback font with a different advance width - the lines then shear apart column by column while the effect runs, and block-letter banners come out mangled. Use a font that has the glyphs (Consolas, DejaVu Sans Mono, Menlo, or a complete JetBrains Mono - the usual latin webfont subsets leave them out), or pass your own glyphs pool.

Effects

Text effects (no canvas)

These only rewrite the element's textContent, frame by frame:

Effect What it does
decrypt(el, opts) Cells flicker through random glyphs, then lock onto the final text.
print(el, opts) Reveals the text in reading order with a moving print head.
matrix(el, opts) Each column resolves top-to-bottom behind a falling bright glyph.
overflow(el, opts) Rows scroll and reshuffle, then settle into order.
errorcorrect(el, opts) Character pairs start swapped in the wrong place and swap back one by one.
randomsequence(el, opts) The characters appear one after another in completely random order.
middleout(el, opts) The text grows from the centre of the block outward.
sweep(el, opts) A noisy band sweeps left to right and leaves the resolved text behind.
pour(el, opts) The text fills up from the bottom row like a liquid, snaking back and forth.
slide(el, opts) The rows slide in as blocks, alternating from the left and the right.
burn(el, opts) An ember front with a ragged edge eats through the block and burns the text in.
vhstape(el, opts) Glitch bands shift rows sideways and sprinkle noise until the tracking settles.
wipe(el, opts) A straight wavefront sweeps across in a chosen direction and leaves the resolved text behind.
slice(el, opts) Each row is cut in half; the two pieces slide inward until they butt together in the middle.
waves(el, opts) An undulating crest rolls across the block and resolves the text as it passes.

Canvas effects

These lay a temporary canvas over the element, animate the characters in free 2D motion, then fade out and reveal the untouched text:

Effect What it does
matrix2(el, opts) The classic falling-glyph screen: katakana rain, then reveal (canvas twin of matrix).
decrypt2(el, opts) Canvas twin of decrypt: the resolved text emerges bright from dimmed ciphertext.
print2(el, opts) Canvas twin of print: a glowing print head with a hot afterglow on fresh characters.
overflow2(el, opts) Canvas twin of overflow: the block spins past sub-pixel-smooth and decelerates onto the text.
beams(el, opts) Bright beams sweep the rows and columns, then a wipe brings the text to full brightness.
rain(el, opts) Every character falls from above straight into its place.
bouncyballs(el, opts) Characters drop in as coloured balls and bounce into position.
bubbles(el, opts) Every character floats down in its own bubble, swaying, and pops into place.
scattered(el, opts) Characters start scattered across the stage and glide to their spot.
expand(el, opts) The whole text bursts outward from the centre.
spray(el, opts) A nozzle in the corner sprays the characters onto the block in curved arcs.
swarm(el, opts) The characters arrive in wobbling swarms that settle area by area.
fireworks(el, opts) Rockets launch, explode into sparks and throw their characters to the text.
blackhole(el, opts) Characters spiral into a singularity, then erupt back out to the text.
rings(el, opts) Characters orbit on concentric spinning rings, then disperse to their positions.
unstable(el, opts) The text shakes, explodes towards the edges and reassembles.
laseretch(el, opts) A laser beam traces the text in and throws off falling sparks.
binarypath(el, opts) Characters enter as streams of 0/1 and travel to their spot at right angles, then resolve.
crumble(el, opts) The text crumbles into scattered dust, then the dust is vacuumed up and reforms.
orbittingvolley(el, opts) Four orbiting launchers fire the characters inward, filling the text from the centre out.
smoke(el, opts) A wall of drifting smoke rolls across and leaves the characters colourised behind it.
spotlights(el, opts) Spotlights sweep the dark block, converge on the centre and flood it to reveal the text.
synthgrid(el, opts) A neon grid grows from the centre, the characters fill in diagonally, then the grid fades.
thunderstorm(el, opts) Lightning bolts strike the block one after another, lighting up the text slab by slab.

Style effects (no text rewrite)

These recolour or light the element in place - they never touch the textContent, so they layer cleanly over an already-visible console:

Effect What it does
crt(el, opts) Persistent CRT treatment - phosphor glow, scanlines, faint flicker. cancel() removes it.
colorshift(el, opts) Persistent animated gradient that keeps sliding across the glyphs. cancel() removes it.
highlight(el, opts) Runs a single specular highlight across the text, then restores the original colours.
gradient(el, opts) Paints a colour gradient across the glyphs - top to bottom, left to right, diagonal or at a free angle. cancel() removes it.

gradient: directions, patterns, palettes

gradient is the one to reach for when the text should simply look good rather than move. It paints the glyphs through background-clip: text, so the text itself stays untouched and selectable. The gradient is measured against the text, not the block, so a left-to-right run spans exactly the widest line instead of trailing off into the empty half of a <pre>.

// Top to bottom, smooth, warm amber
RetroTextEffects.gradient('#log', { direction: 'down', palette: 'amber' });

// Left to right through the whole vaporwave palette
RetroTextEffects.gradient('#log', { direction: 'right', palette: 'vaporwave' });

// One hard colour band per text line
RetroTextEffects.gradient('#log', { mode: 'bands', palette: 'rainbow', repeat: 'lines' });

// Diagonal stripes that keep flowing
RetroTextEffects.gradient('#log', {
  direction: 'diagonal', mode: 'stripes', palette: 'cyberpunk', size: 14, animate: true,
});

// Your own colours, at a free angle
RetroTextEffects.gradient('#log', { direction: 37, colors: ['#ff0055', '#00e5ff'] });
Setting Values
direction down (top to bottom), up, right (left to right), left, diagonal, diagonal-up, or any CSS angle as a number
mode smooth (blend), bands (hard-edged colour blocks), stripes (fixed-width stripes, size in px)
palette phosphor, amber, ice, fire, toxic, gold, copper, sunset, vaporwave, cyberpunk, rainbow, mono - or pass colors
repeat how often the palette fits along the axis - 'lines' gives exactly one colour per text line
animate false by default. true lets the whole pattern flow along its own direction, at speed

The twelve built-in palettes:

Palette Colours Reads as
phosphor #0f8f2e #33ff33 #ccffcc green screen, dark to bright
amber #a35a00 #ffb000 #ffe9b0 the other classic tube
ice #2f6fb0 #3fa7d6 #d6f6ff cold blue, deep to pale
fire #c02a4a #e4572e #ffa62b #ffef7a embers to sparks
toxic #3f8f10 #7cff00 #e4ff9e radioactive green
gold #b08000 #ffd700 #fff6c0 polished metal
copper #8a4a1e #b87333 #ffd9a0 warm patinated metal
sunset #5b2b9e #7b2ff7 #ff3c78 #ff8c42 violet into orange
vaporwave #05ffa1 #01cdfe #b967ff #ff71ce the full 80s spectrum
cyberpunk #00f0ff #7a5cff #ff007a neon cyan to magenta
rainbow #ff3b30 #ff9500 #ffee00 #33ff33 #00cfff #6633ff #ff33cc seven colours, best with bands
mono #ffffff #5a5a5a white to grey, no hue at all

All of this is readable at runtime, so a picker never has to duplicate the values: RetroTextEffects.gradientPalettes, gradientDirections and gradientModes return the valid names as arrays, and gradientColors('sunset') hands back that palette's colours.

Input effects (placeholder only)

placeholder is the only effect that runs on a form field. It types the placeholder of an <input> or <textarea> character by character, holds it, wipes it out again and moves on to the next line. The only thing it ever writes is the placeholder attribute - no wrapper element, no injected markup, no inline styles - so the field keeps exactly the CSS you gave it.

Effect What it does
placeholder(el, opts) Types, holds and deletes the placeholder of an input or textarea, line after line.
<input id="search" placeholder="Search the docs">
<!-- or keep the lines in the markup, so the field still reads sensibly without JS: -->
<input id="cmd" data-rte-placeholders="ssh root@mainframe | cat /var/log/retro.log">
RetroTextEffects.placeholder('#search', {
  texts: ['Search the docs', 'or an effect name', 'try: fireworks'],
  cps: 24,          // typing speed
  cursor: '_',      // '' switches the cursor off
});

const fx = RetroTextEffects.placeholder('#cmd');   // lines from data-rte-placeholders
fx.cancel();        // stops it and puts the original placeholder back

Three details that make it behave in a real form: it freezes while the field is focused or filled in (a placeholder nobody can see does not need to flicker, and a blinking one under a cursor is only in the way) and picks up again on blur, it honours prefers-reduced-motion by setting the first line as a plain placeholder, and cancel() restores the placeholder the field was served with.

Art effects (the text is generated)

aura is the odd one out twice over. It does not read the element's text, it rasterises a Unicode glyph on an offscreen canvas, translates the cells into a character ramp and wraps the figure in a ring of terminal characters that keeps moving. Like crt it is persistent - it runs until cancel().

It is also the only effect here that is not part of the TTE port: TerminalTextEffects has no counterpart for it. The idea comes from the animated ASCII ghost on ghostty.org, the website of the Ghostty terminal emulator. Rebuilt from scratch for arbitrary glyphs, no code taken from there.

Effect What it does
aura(el, opts) Turns a glyph into a glowing ASCII figure with an animated aura. Also offers update() and text().
asciiArt(glyph, opts) Not an effect but a plain function - returns the art as a string, ready for any other effect.
const ghost = RetroTextEffects.aura('#stage', { emoji: 'πŸ‘»', cols: 46 });

ghost.update({ variant: 'sonar', motion: 'spin', color: '#35d0ff' });
ghost.text();     // the figure as plain text, without the aura
ghost.cancel();   // stops it and restores the element's original content

// Or skip the animation and feed the art into any other effect:
document.querySelector('#stage').textContent = RetroTextEffects.asciiArt('πŸŽƒ', { cols: 40 });
RetroTextEffects.decrypt('#stage');

Six aura variants, listed in RetroTextEffects.auraVariants:

Variant What it does
shimmer Every cell flickers on its own - the classic look from ghostty.org.
pulse Brightness follows the distance, so the aura breathes outward.
sonar Rings leave the figure one after another.
orbit An arc of light circles the figure like a radar sweep.
updraft A noise field drifts upward, like rising heat.
halo No movement, just the stepped distance.

Three kinds of motion, listed in RetroTextEffects.auraMotions: off keeps the figure still, float tilts it and hops it by whole rows, and spin squeezes it horizontally with a cosine so it reads as a flipping coin. The poses are rasterised once and replayed as a loop - a CSS transform would tilt the characters themselves and break the grid.

Two things worth knowing: emoji fonts are platform specific, so the same glyph looks different on Windows, macOS and Linux - bake the art in with asciiArt() if you need a fixed result. And prefers-reduced-motion is honoured: the figure is then drawn once and stands still.

Each effect returns a small controller:

const fx = RetroTextEffects.print('#log', { cps: 80, onDone: () => {} });
fx.cancel();        // stop early
await fx.finished;  // resolves when the animation ends

Common options

Option Type Default Applies to
speed number 1 all
onDone function - all
fps number 30 text effects (canvas effects run delta-timed on rAF)
glyphs string built-in pool decrypt, decrypt2, matrix, matrix2, sweep
preserveWhitespace boolean true decrypt
cps number 60 / 22 print, print2, placeholder
head string β–ˆ print
cycles number 3 overflow, overflow2
ratio number 0.1 errorcorrect (share of swapped pairs)
band number 6 sweep (width of the noise band)
duration number (ms) 1500 matrix2
fontSize number 20 matrix2
color string #00ff00 / #33ff33 matrix2, crt, synthgrid, highlight
scanlineOpacity number 0.15 crt
glow boolean true crt
flicker boolean true crt
direction string | number diagonal / right / down wipe (left/right/up/down/diagonal), highlight (left/right), gradient (also diagonal-up or an angle)
amplitude number 4 waves (how far the crest bends per row)
colors string[] retro palette colorshift, gradient (overrides palette)
palette string phosphor gradient (twelve built-in colour patterns)
mode string smooth gradient (smooth/bands/stripes)
repeat number | lines 1 gradient ('lines' = one colour per text line)
size number (px) 18 gradient (stripe width, mode: 'stripes')
animate boolean false gradient (lets the pattern flow along its direction)
texts string[] from the field placeholder (else data-rte-placeholders, else the placeholder)
deleteCps number 45 placeholder (deleting speed)
hold number (ms) 1800 placeholder (pause on the finished line)
pause number (ms) 400 placeholder (pause on the empty field)
cursor string _ placeholder ('' switches it off)
blink boolean true placeholder
loop boolean true placeholder (false stops after the last line)
emoji string πŸ‘» aura
cols number 40 aura, asciiArt (raster width in characters)
variant string shimmer aura
motion string float aura (off/float/spin)
width number 4.5 aura (aura width in line heights)
fit boolean true aura (scales the font so the figure fills the element), gradient (spans the text, not the block)
ramp string Β·~oxX%$@ aura, asciiArt

All other canvas effects take speed and onDone; font, colour and character grid are read from the target element so the hand-off to the real text is seamless. glyphs is also accepted by decrypt2 and matrix2.

Use offline / self-hosted

The build is a single self-contained file with no dependencies and no external requests, so there is nothing to hotlink. Download retro-text-effects.min.js from the releases and include it with a plain script tag:

<script src="retro-text-effects.min.js"></script>
<script>
  RetroTextEffects.decrypt('#log');
</script>

That works anywhere you can serve a static JS file - static sites, offline apps, or a server-rendered view where you drop it in as a local asset.

Build from source

npm install
npm run lint
npm run build   # -> dist/retro-text-effects.js + dist/retro-text-effects.min.js

Open demo/index.html in a browser to see the showroom.

License

Apache-2.0. This is a browser port of TerminalTextEffects (Python, MIT) - the effects were rebuilt from scratch for the DOM, no code was copied.

About

Zero-dependency retro terminal text effects for the browser - decrypt, print, matrix and overflow in one self-contained file.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages