GPU fields
From 4.11, asciify-engine/field draws an image, a video or generated motion as characters entirely on the GPU, with a fluid wake under the cursor. Use it for full-bleed heroes and brand fields that must stay smooth while people move across them. Characters come from a glyph atlas drawn in your font, so any charset works, including your own name.
Mount a field
import { mountGlyphField, isGlyphFieldSupported } from 'asciify-engine/field';
// Size the canvas with CSS; the field follows it.
if (isGlyphFieldSupported()) {
const field = mountGlyphField(canvas, {
source: '/media/hero.mp4', // image or video; omit for generated motion
charset: ' .,:-+ACME', // empty to dense; words work
cellSize: 12, cellAspect: 0.8,
color: 'ink', ink: '#f3ba32', shade: 1,
vignette: 0.3,
fluid: { radius: 0.08, refraction: 0.03, glow: 0.6 },
label: 'Our studio, drawn in our name',
});
await field.ready; // first frame drawn: hide your poster
// field.update({ charset: ' .:YOURS' }); field.destroy();
}| Option | Type | Default | Description |
|---|---|---|---|
source | URL | element | none | Image or video (.mp4, .webm, .mov play muted and looped). Without one, scene draws generated motion. |
charset | string | ' .,:-=+*#%@' | Ordered from empty to dense. Braille, block shading, emoji and words each take one cell. |
cellSize / cellAspect | number | 12 / 1 | Cell height in CSS pixels and width over height. Monospaced ramps look best near 0.6. |
color | 'ink' | 'source' | 'ink' | One ink, or each cell takes the hue of the media under it. |
shade | 0–1 | 0.5 | How far darker tones dim the ink, so same-density letters still carry the image. |
backdrop | 0–1 | 0 | A soft, blurred copy of the source under the characters, from the texture mip chain. |
levels | 'auto' | 'none' | 'auto' | Stretches the source tones across the whole charset. |
hover | 'trail' | 'fluid' | 'lantern' | 'none' | 'fluid' | Trail is the Asciify Trail, the same ink field as the studio: sparse characters fill in and dense ones open up in the wake. Fluid is a bold ink-in-water wake that bends the image. Lantern is a soft light with no distortion. |
fluid | object | false | on | radius, force, dissipation, curl (how strongly it eddies), refraction (how far it bends sampling) and glow (how strongly it lights characters). |
lantern | object | soft | radius, strength, trail (seconds its tail takes to fade) and follow (how tightly the light catches the pointer). |
drift / scene | number / string | 0 / 'flow' | Ambient drift keeps a still alive; flow and orb are generated scenes for use without media. |
Halftone for interfaces
From 4.12, mark: 'dot' draws one circle per cell whose area follows the tone, a halftone that sits quietly behind product pages in light or dark themes. Pair it with the drift scene, keep it clear around your content, and let the interface answer events with pulse().
import { mountGlyphField } from 'asciify-engine/field';
const field = mountGlyphField(heroCanvas, {
mark: 'dot', scene: 'drift',
cellSize: 14, dotScale: 0.64,
color: 'ink', ink: '#9a988f', background: 'transparent',
// The field fades out around this element and follows layout changes.
clear: { element: document.querySelector('#hero .copy'), padding: 40, feather: 0.18 },
hover: 'lantern',
});
// A ring through the dots when something happens:
saveButton.addEventListener('click', () => field.pulse({ element: saveButton }));| Option | Type | Default | Description |
|---|---|---|---|
mark | 'glyph' | 'dot' | 'glyph' | Dots draw a halftone: area follows tone, edges antialiased to one device pixel at any pixel ratio. |
dotScale | 0.1–1.4 | 0.9 | Largest dot as a fraction of the cell. Around 0.6 keeps a calm, open grid. |
scene: 'drift' | string | A few broad lobes that wander slowly, made for halftone. scale makes the shapes finer; use about 1.8 on phones. | |
clear | element | zone | false | false | Keeps the field quiet around content: an element (with padding, feather and shape), or a zone in field fractions. |
pulse() | method | Sends a ring through the field from a point or an element, e.g. on a save or a new message. Ignored under reduced motion. |
One look for every field
setGlobalLook from asciify-engine/kit re-skins every kit field and background on the page at once (a component created with globalLook: false, or whose charset spells letters, keeps its own): a charset, one of the 24 Studio styles in KIT_STYLES, or both. A glyph-like style brings its own ramp, which charset overrides; tile and print styles change the mark. The set's ink is balanced against classic ASCII, so every charset reads at the same weight.
import { setGlobalLook, getGlobalLook, subscribeGlobalLook } from 'asciify-engine/kit';
setGlobalLook({ charset: ' .:ASCIIFY' });
setGlobalLook({ style: 'braille' }); // any key of KIT_STYLES
setGlobalLook(null); // each field gets its own characters back
const current = getGlobalLook(); // null when unset
const unsubscribe = subscribeGlobalLook(look => syncPicker(look));Smooth by construction
One full-screen pass draws the characters and one small pass moves the wake; nothing is read back to the CPU. A still field stops drawing once the wake settles, videos upload only new frames, and off-screen fields stop. Measured in Playwright Chromium on an Apple M4 Pro at 1440 × 900 and pixel ratio 2, a full-viewport photo field held 120 fps, with a 9 ms 95th-percentile frame, under continuous pointer movement. Measure your own target devices.