
Security News
Socket Releases Free Certified Patches for Critical vm2 Sandbox Escape
A critical vm2 sandbox escape can allow untrusted JavaScript to break isolation and execute commands on the host Node.js process.
@disclearing/flicker
Advanced tools
Utility for flickering text, images, and DOM elements with configurable timing and intensity
Utility for flickering text, images, and DOM elements with configurable timing, intensity, and advanced image manipulation. Includes a unified text writer (write/queue/add/remove), text presets (zalgo, terminal, neo, cosmic, horror), CSS filters, text effects (scramble, typewriter, decode), presets, plugins, timeline/keyframes, group orchestration, audio-reactive mode, canvas/WebGL renderers, and framework adapters.
📖 Full documentation — installation, text writer, framework adapters, presets, advanced usage, and migration from glitched-writer.
npm install @disclearing/flicker
import { createFlicker } from '@disclearing/flicker';
const el = document.querySelector('.my-text');
const controller = createFlicker(el, { interval: 100 });
controller.start();
// later: controller.stop(); controller.destroy();
import { flickerElement, flickerSelector } from '@disclearing/flicker';
const ctrl = flickerElement('#logo');
if (ctrl) ctrl.start();
const controllers = flickerSelector('.flicker-me');
controllers.forEach((c) => c.start());
engine: 'timeout' (default) or 'raf' for requestAnimationFrame-based timing.respectReducedMotion: When true (default), honors prefers-reduced-motion and disables or softens flicker.autoPauseOnHidden: When true (default), pauses when the tab is hidden and resumes when visible.onStart, onPause, onResume, onDestroy, onVisibilityChange; image sequences also support onTransitionStart, onTransitionEnd, onLoop.Always call destroy() when discarding a controller to clear timers and listeners.
Use built-in presets for common looks:
import { getFlickerPreset, getSequencePreset, getCombinedPreset } from '@disclearing/flicker';
// Flicker presets: neonSign, horrorGlitch, oldTV, warningAlarm
const opts = getFlickerPreset('horrorGlitch', { interval: 40 });
createFlicker(el, opts).start();
// Sequence presets: neon, horror, oldTV, warning
const seqOpts = getSequencePreset('horror', { images: ['/a.jpg', '/b.jpg'] });
createImageSequence(img, seqOpts).start();
// Combined
const combined = getCombinedPreset('horrorGlitch', 'horror', { sequence: { images: ['/1.jpg', '/2.jpg'] } });
createCombinedFlicker(img, combined).start();
// Text writer presets: zalgo, terminal, neo, cosmic, horror, encrypted, nier, default
const textOpts = getTextPreset('zalgo', { interval: 40 });
createTextWriter(el, textOpts).write('Hello world');
Unified writer API: write(), writeAsync(), queue(), endless(), add(), remove() with scramble, typewriter, decode, or glyph-sub effects. Respects engine, respectReducedMotion, and autoPauseOnHidden like other controllers.
import { createTextWriter, getTextPreset } from '@disclearing/flicker';
const el = document.querySelector('.text-target');
const writer = createTextWriter(el, { mode: 'scramble', interval: 60, cursor: true });
writer.write('Hello'); // animate in one string
await writer.writeAsync('Done'); // Promise resolves when animation finishes
writer.queue(['Line 1', 'Line 2'], 500, true); // queue phrases, optional loop
writer.endless(['A', 'B', 'C'], 300); // same as queue(..., true)
writer.add(' more'); // append and animate new part only
writer.remove(3); // remove last 3 chars
writer.on('complete', () => console.log('done')); // multiple listeners
writer.off('complete', handler);
writer.pause();
writer.resume();
writer.destroy();
flicker-writer-finished with detail: { text, length } so you can listen without callbacks.'scramble' (reveal from random glyphs), 'typewriter' (character-by-character, optional human-like variance and punctuation pause), 'decode' (each char resolves from random to final), 'glyph-sub' (continuous substitution).glyphPool, interval, minInterval/maxInterval, humanLike, pauseOnSpaces, punctuationPauseMs, cursor: true | '|' | { char, blink } (typing cursor; use blink: true for blinking), seed (number for deterministic animations), html: 'strip' | 'preserve' (preserve tags when writing e.g. writer.write('<b>Hi</b>')), letterize: 'in-place' | 'fragment', onStep, onComplete, plus engine and a11y options.writer.on('start' | 'step' | 'complete' | 'destroy' | 'visibilitychange', fn) and writer.off(event, fn) for multiple listeners.decodeEntities(), letterizeToFragment(), setLetterizedContent(), setLetterizedContentFromHtml() (parse HTML string and letterize only text nodes), createSeededRandom(seed) for deterministic RNG; runDecode() for one-shot decode effect.Register custom transitions and effects:
import { registerTransition, registerEffect, createFlicker } from '@disclearing/flicker';
registerTransition('my-fade', async (element, newSrc, duration) => {
element.style.opacity = '0';
await new Promise((r) => setTimeout(r, duration / 2));
element.src = newSrc;
element.style.opacity = '1';
});
registerEffect('my-glow', (el, visible) => {
el.style.boxShadow = visible ? '0 0 20px rgba(255,0,0,0.5)' : 'none';
});
createFlicker(el, {}).start(); // registered effects run each tick
createImageSequence(img, { images: ['/a.jpg', '/b.jpg'], transition: 'my-fade' }).start();
Timeline: run steps in order (flicker for N ms, pause, custom callback, etc.):
import { createTimeline } from '@disclearing/flicker';
const timeline = createTimeline([
{ type: 'flicker', element: titleEl, options: { interval: 50 }, duration: 300 },
{ type: 'pause', duration: 500 },
{ type: 'callback', fn: () => console.log('Done step 2') },
], { loop: false, onComplete: () => console.log('Timeline done') });
timeline.start();
Group: start multiple controllers with a shared clock and optional phase offsets:
import { createGroup, createFlicker } from '@disclearing/flicker';
const c1 = createFlicker(el1, { interval: 100 });
const c2 = createFlicker(el2, { interval: 100 });
const group = createGroup([
{ controller: c1 },
{ controller: c2, phaseOffsetMs: 50 },
]);
group.start();
Drive interval and intensity from microphone or audio element:
import { createAudioReactiveFlicker, isAudioReactiveSupported } from '@disclearing/flicker';
if (!isAudioReactiveSupported()) return;
const audioEl = document.querySelector('audio');
const ctrl = createAudioReactiveFlicker(domEl, {
source: audioEl,
onError: (err) => console.warn('Audio-reactive unavailable', err.message),
});
ctrl.start();
Canvas, WebGL, and WebGPU renderers apply noise, scanline, or distortion to a source image/video. Canvas auto-resizes with the source, pauses when the tab is hidden (autoPauseOnHidden), and supports scale/throttleFps for performance. WebGL supports continuous rendering via createWebGLRenderer and exposes onContextLost/onError. WebGPU supports ready() promise, autoResize, and onDeviceLost. For custom GPU work without Three.js, use direct WebGPU (createWebGPUSceneRenderer, createWebGPULitSceneRenderer, mesh/texture helpers, camera/matrix utilities, orbit controls, compute pipelines) — see Advanced → Direct WebGPU.
import {
createCanvasRenderer,
createWebGLRenderer,
createWebGPURenderer,
isCanvasSupported,
isWebGLSupported,
isWebGPUSupported,
} from '@disclearing/flicker';
if (!isCanvasSupported()) return;
const renderer = createCanvasRenderer(videoEl, { type: 'scanline', scanlineSpacing: 4 });
renderer.start();
document.body.appendChild(renderer.canvas);
if (isWebGLSupported()) {
const webgl = createWebGLRenderer(videoEl, { type: 'distortion', autoResize: true });
webgl.start();
if (webgl.canvas) document.body.appendChild(webgl.canvas);
}
if (isWebGPUSupported()) {
const gpu = createWebGPURenderer(videoEl, { type: 'noise', noiseAmount: 0.12 });
await gpu.ready();
gpu.start();
if (gpu.canvas) document.body.appendChild(gpu.canvas);
}
React (install react when using):
import { useFlicker, useFlickerController, useImageSequence, useTimeline, useTextWriter } from '@disclearing/flicker/react';
function MyComponent() {
const ref = useRef(null);
useFlicker(ref, { interval: 100 });
return <div ref={ref}>Flickering text</div>;
}
// Text writer: bind ref and get controller (write, queue, writeAsync, endless, etc.)
function WriterDemo() {
const ref = useRef(null);
const writerRef = useTextWriter(ref, { mode: 'typewriter', cursor: true });
useEffect(() => {
writerRef.current?.write('Hello world');
}, []);
return <div ref={ref} />;
}
Vue 3 – text writer (composable or directive):
import { useTextWriter, textWriterDirective, unmountTextWriterDirective } from '@disclearing/flicker/vue';
// Composable: get write, queue, writeAsync, endless, etc.
const { controller, write, writeAsync } = useTextWriter(elementRef, { mode: 'scramble', cursor: { blink: true } });
onMounted(() => write('Hello'));
// Or directive: v-text-writer="options" then use ref to call writer methods
app.directive('text-writer', { mounted: textWriterDirective, unmounted: unmountTextWriterDirective });
Svelte – text writer (action):
<script>
import { textWriter } from '@disclearing/flicker/svelte';
let writerOpts = { mode: 'typewriter', cursor: { char: '|', blink: true } };
</script>
<div use:textWriter={writerOpts} bind:this={el}></div>
<!-- Or get controller from action return: const result = textWriter(node, opts); result.controller.write('Hi'); -->
Vue 3 (optional):
import { useFlicker, flickerDirective } from '@disclearing/flicker/vue';
// Composition: call start() in onMounted
const { start, stop } = useFlicker(elementRef, { interval: 100 });
// Directive
app.directive('flicker', { mounted: flickerDirective, unmounted: unmountFlickerDirective });
Svelte (optional):
import { flicker, imageSequence } from '@disclearing/flicker/svelte';
<div use:flicker={{ interval: 100 }}>Flickering</div>
<img use:imageSequence={{ images: ['/a.jpg', '/b.jpg'], interval: 500 }} alt="" />
Expo / React Native (optional):
import { useExpoFlicker, useExpoImageSequence } from '@disclearing/flicker/expo';
function GlitchImage() {
const { currentImage, controller: seq } = useExpoImageSequence({
images: ['https://example.com/1.png', 'https://example.com/2.png'],
interval: 500,
loop: true,
});
const { opacity, controller: flicker } = useExpoFlicker({ interval: 80, offOpacity: 0.15 });
useEffect(() => {
seq.start();
flicker.start();
return () => {
seq.destroy();
flicker.destroy();
};
}, [seq, flicker]);
return <Image source={{ uri: currentImage ?? undefined }} style={{ opacity, width: 200, height: 200 }} />;
}
Validate options before use:
import {
validateFlickerOptions,
validateTextWriterOptions,
validateOrThrow,
} from '@disclearing/flicker';
const result = validateFlickerOptions({ interval: -1 });
if (!result.valid) console.error(result.errors);
const textResult = validateTextWriterOptions({ mode: 'decode', decodeDuration: -5 });
if (!textResult.valid) console.error(textResult.errors);
validateOrThrow(userOptions, validateFlickerOptions, 'Flicker');
instant, crossfade, slide-left/right/up/down, zoom, flicker, or custom via registerTransition.interval, randomInterval, minInterval/maxInterval, transition, transitionDuration, loop, shuffle, startIndex, direction, preload, preloadAhead, duration, and callbacks including onStart, onPause, onResume, onTransitionStart, onTransitionEnd, onLoop, onDestroy, onVisibilityChange, onError.preloadImage(url, { retries: 2, backoffMs: 500 }).configurePreloader({ maxCacheSize: 100, evictionStrategy: 'leastRecentlyUsed' }).evictStale(maxAgeMs).applyFilters(el, { blur, contrast, hueRotate, saturate, chromaticAberration, rgbSplit }); use filters in flicker options for the "off" phase.preparePerCharFlicker(container), runScrambleReveal(container, options), runGlyphSubstitution(container, options), runTypewriter(container, options), runDecode(container, options) (decode/decrypt: each char resolves from random glyphs). Options support onStep(index, char, isComplete) and startFromIndex for writer add(). Container gets data-flicker-state="writing" and class flicker-writing during animation; spans get data-flicker-char-index.decodeEntities(str), letterizeToFragment(text), setLetterizedContent(container, text), setLetterizedContentFromHtml(container, htmlString). Use html: 'strip' | 'preserve' and decodeEntitiesIn in effect options.Blinking cursor (use cursor: { char: '|', blink: true } and add CSS):
.flicker-cursor-blink {
animation: flicker-cursor-blink 0.8s step-end infinite;
}
@keyframes flicker-cursor-blink {
50% { opacity: 0; }
}
HTML with preserved tags (e.g. <b>bold</b> stays bold):
createTextWriter(el, { html: 'preserve' }).write('<b>Hello</b> <i>world</i>');
Deterministic animation (same seed = same pattern; useful for tests or replay):
createTextWriter(el, { mode: 'scramble', seed: 42 }).write('Reproducible glitch');
start(), stop(), setOptions(), destroy(), isRunning.pause(), resume(), jumpTo(), next(), previous(), preloadAll(), isPaused, currentIndex, totalImages, currentImage.state (visible, imageIndex, imageUrl).MIT
FAQs
Utility for flickering text, images, and DOM elements with configurable timing and intensity
The npm package @disclearing/flicker receives a total of 22 weekly downloads. As such, @disclearing/flicker popularity was classified as not popular.
We found that @disclearing/flicker demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A critical vm2 sandbox escape can allow untrusted JavaScript to break isolation and execute commands on the host Node.js process.

Research
Five malicious NuGet packages impersonate Chinese .NET libraries to deploy a stealer targeting browser credentials, crypto wallets, SSH keys, and local files.

Security News
pnpm 11 turns on a 1-day Minimum Release Age and blocks exotic subdeps by default, adding safeguards against fast-moving supply chain attacks.