| Import | Description |
|---|---|
lascii |
Main entry. Side-effect free; exports classes and init / autoInitDom. |
lascii/auto |
Auto-initializes on DOMContentLoaded via autoInitDom() (side-effectful). |
lascii/dom |
DOM adapter exports (LasciiTextEffect, LasciiImageEffect, initDom, autoInitDom). Side-effect free. |
lascii/core/text |
LasciiTextEffect only. |
lascii/core/image |
LasciiImageEffect only. |
Use lascii or lascii/core/* when you want full control and no side effects on import. Use lascii/auto for declarative data-lascii-* setup.
import lascii, {
LasciiTextEffect,
LasciiImageEffect,
init,
autoInitDom,
} from "lascii";| Export | Type | Description |
|---|---|---|
LasciiTextEffect |
class |
Scramble/reveal text animation. |
LasciiImageEffect |
class |
ASCII canvas reveal for images. |
init |
function |
Scans the DOM and starts effects (initDom). |
autoInitDom |
function |
Registers init on DOMContentLoaded, or runs immediately if the document is ready. |
InitDomOptions |
type |
Options for init / autoInitDom ({ lazy?: boolean }). |
LasciiEvent |
object |
Event name constants: start, progress, complete, error. |
default |
object |
{ LasciiTextEffect, LasciiImageEffect, init, autoInitDom }. |
init() (alias of initDom) runs:
LasciiImageEffect.init("[data-lascii-image]")LasciiTextEffect.init("[data-lascii-text]")
Pass { lazy: true } to defer creation until each element is near the viewport (Intersection Observer with rootMargin: "100px"). This reduces startup work on pages with many effects, especially image sampling. If IntersectionObserver is unavailable, init falls back to the eager path.
import { init } from "lascii";
init({ lazy: true });autoInitDom() calls init() when the document is ready and accepts the same options:
import { autoInitDom } from "lascii";
autoInitDom({ lazy: true });Importing lascii does not call autoInitDom() automatically. For declarative setup:
import "lascii/auto";Or call it yourself:
import { autoInitDom } from "lascii";
autoInitDom();To import a single effect with maximum tree shaking:
import { LasciiTextEffect } from "lascii/core/text";
import { LasciiImageEffect } from "lascii/core/image";| Attribute | Element | Behavior |
|---|---|---|
data-lascii-text |
Any text container | Reads textContent, runs text scramble effect. |
data-lascii-image |
<img> |
Samples image, ASCII animation, then fades to original. |
Multiple phrases in one element are separated by |:| (configurable via separator):
<p data-lascii-text>First|:|Second|:|Third</p>When the separator is present, phrases loop with phraseDelay between transitions.
Place the image inside a positioned wrapper with overflow hidden and a defined aspect ratio (e.g. aspect-ratio: 4/5):
<div style="position: relative; aspect-ratio: 4/5; overflow: hidden;">
<img data-lascii-image src="photo.jpg" alt="photo" />
</div>Cross-origin images need CORS headers on the image server (crossOrigin = "anonymous" is set internally).
import { LasciiTextEffect } from "lascii";
// or
import LasciiTextEffect from "lascii/core/text";new LasciiTextEffect(element, options?)- element — DOM node whose
textContentis the source string. - options — Partial override of
LasciiTextEffect.DEFAULTS.
On construction, the element’s text is cleared. The first animation is scheduled on a microtask, so you can attach lifecycle listeners immediately after new.
| Key | Value | Effect |
|---|---|---|
START |
"start" |
Reveal progresses from the start of the string. |
MIDDLE |
"middle" |
Reveal radiates from the center outward. |
| Option | Type | Default | Description |
|---|---|---|---|
introChars |
string |
"█▓▒░x92" |
Character sequence shown at the start of each cell’s scramble. |
introPhaseFrames |
number |
10 |
Frames to step through introChars before random chars. |
chars |
string |
"!<>-_\\/[]{}—=+*^?#________" |
Pool of random scramble characters. |
frameStartMax |
number |
40 |
Max frames before a character begins scrambling (spread along string). |
frameEndMax |
number |
40 |
Random extra scramble length cap per character. |
randomCharChance |
number |
0.28 |
Probability of picking a new random char each frame. |
phraseDelay |
number |
800 |
Ms between phrases when looping (` |
separator |
string |
`"|: | "` |
revealOrigin |
string |
"start" |
"start" or "middle" (RevealOrigin). |
reducedMotion is a constructor option (not a default): true skips animation, false forces it, omitted follows prefers-reduced-motion. See Accessibility.
Scramble characters are rendered in <span class="dud"> — style .dud in your CSS if needed.
| Method | Returns | Description |
|---|---|---|
setText(newText) |
Promise<void> |
Animates from current text to newText. Resolves when complete (3s safety timeout). |
Both effects extend EventTarget and emit lifecycle events (see Lifecycle events).
LasciiTextEffect.init(selector = "[data-lascii-text]")Creates one LasciiTextEffect per matching element.
const effect = new LasciiTextEffect(document.querySelector(".headline"), {
phraseDelay: 1200,
revealOrigin: LasciiTextEffect.RevealOrigin.MIDDLE,
});
effect.addEventListener("complete", (event) => {
console.log("Effect completed:", event.detail.text);
});
await effect.setText("Updated copy");import { LasciiImageEffect } from "lascii";
// or
import LasciiImageEffect from "lascii/core/image";new LasciiImageEffect(img, index = 0, options?)- img —
<img>element. Opacity is set to0until reveal; a canvas is appended to the parent. - index — Stagger index: delay =
index * IMAGE_STAGGER_MS. - options — Partial override of
LasciiImageEffect.DEFAULTS.
| Option | Type | Default | Description |
|---|---|---|---|
ASCII_CHARS |
string |
" . . . . . . :::=+xX#0369" |
Light-to-dark character ramp for luminance mapping. |
FONT_SIZE |
number |
40 |
Monospace font size used for measurement and drawing. |
ASPECT_WIDTH |
number |
4 |
Target crop aspect (width). |
ASPECT_HEIGHT |
number |
5 |
Target crop aspect (height). |
ASCII_COLUMNS |
number |
25 |
Minimum column count (may increase with container width). |
MAX_ASCII_COLUMNS |
number |
96 |
Upper cap when scaling to container width. |
TARGET_CELL_CSS_PX |
number |
9 |
Target cell size in CSS pixels for column scaling. |
IMAGE_STAGGER_MS |
number |
100 |
Delay multiplier per image index. |
CELL_APPEAR_MS |
number |
0.5 |
Delay between starting each cell animation. |
SCRAMBLE_COUNT |
number |
10 |
Scramble frames for “dense” (dark) cells. |
SCRAMBLE_SPEED_MS |
number |
50 |
Interval between scramble frame updates. |
REVEAL_DELAY_MS |
number |
0 |
Delay before fading canvas out and showing the image. |
BACKGROUND_COLOR |
string |
"transparent" |
Canvas cell background. |
TEXT_COLOR |
string |
"#c8c8c8" |
ASCII character color. |
reducedMotion is a constructor option (not a default): true skips the ASCII animation and shows the original image, false forces animation, omitted follows prefers-reduced-motion.
Column count is recalculated from the image’s displayed width:
cols = clamp(ASCII_COLUMNS, round(width / TARGET_CELL_CSS_PX), MAX_ASCII_COLUMNS).
LasciiImageEffect.init(selector = "[data-lascii-image]")Creates one LasciiImageEffect per matching image, with index from forEach order.
Both effects extend EventTarget and emit lifecycle events (see Lifecycle events). For images, start / complete detail.text is img.alt or, if empty, img.src.
document.querySelectorAll("[data-lascii-image]").forEach((img, index) => {
new LasciiImageEffect(img, index, {
SCRAMBLE_COUNT: 20,
TEXT_COLOR: "#ffffff",
});
});LasciiTextEffect and LasciiImageEffect extend EventTarget. Attach listeners after construction; the first animation turn waits one microtask so start is not missed.
| Event | When | detail |
|---|---|---|
start |
Animation begins | { text: string } |
progress |
During the animation | { progress: number } |
complete |
Animation finished | { text: string } |
error |
Recoverable runtime failure | { error: Error } |
progress is a number from 0 to 1. Looping text effects emit start / complete once per phrase.
import { LasciiEvent, LasciiTextEffect } from "lascii";
const effect = new LasciiTextEffect(element);
effect.addEventListener(LasciiEvent.Complete, (event) => {
console.log("Effect completed:", event.detail.text);
});
effect.addEventListener("error", (event) => {
console.warn(event.detail.error);
});Effects follow prefers-reduced-motion: reduce (WCAG 2.3.3 / motion preferences):
- Text — the target phrase is applied immediately; scramble/
requestAnimationFrameis skipped. Looped phrases still advance afterphraseDelay, without animation. - Image — the original
<img>stays visible; canvas sampling and cell animation do not run.
Override with { reducedMotion: true } or { reducedMotion: false }.
LasciiTextEffect treats the host as a live region:
| Attribute | When | Purpose |
|---|---|---|
aria-live="polite" |
If the author did not set aria-live |
Announce phrase changes without interrupting |
aria-atomic="true" |
If missing | Read the whole phrase |
aria-busy="true" and aria-label |
During scramble | Expose the destination text instead of random characters |
| (remove busy/label) | When complete | Accessible name falls back to visible textContent |
LasciiImageEffect sets aria-hidden="true" on the decorative canvas and aria-busy="true" on the image while the ASCII overlay is running (cleared on reveal, error, or dispose). Prefer a meaningful alt on the <img>.
<script type="module">
import "lascii/auto";
</script>import { LasciiImageEffect, LasciiTextEffect, init } from "lascii";
init();Or with maximum tree shaking:
import LasciiTextEffect from "lascii/core/text";
import LasciiImageEffect from "lascii/core/image";
import { initDom } from "lascii/dom";
initDom();Only ./dist/auto.js and ./dist/auto.cjs are marked as side-effectful in package.json. All other entry points are tree-shakeable:
import { LasciiTextEffect } from "lascii"— can drop unused image codeimport from "lascii/core/text"— text effect onlyimport "lascii/auto"— keeps the auto-init side effect (intentional)