quanhoangindex/ascii-reveal

★ 550⑂ 47

About quanhoangindex/ascii-reveal

quanhoangindex/ascii-reveal is an open-source project on GitHub, mainly written in TypeScript. It currently holds 550 stars and 47 forks with 0 open issues, and was last pushed on an unknown date (repository created unknown).

Project Overview

Git Homed tracks it on the Today's Trending board.

GitHub Repository Details

Repository quanhoangindex/ascii-reveal · default branch - · size 0 KB · watchers 0 · source: GitHub REST API and repository README

README

ascii-reveal

https://github.com/quanhoangindex/ascii-reveal/blob/HEAD/Three cards load as ASCII skeletons, then their real content decodes in through a character grid

Recorded from the real component: <AsciiSkeleton> while loading, then <AsciiReveal> decodes the data in. Try the live demo →


  {data ?  : }

A loading effect for React. Text, images and whole cards decode into place through a character grid, in one wave across the page.

Install

From npm:

npm i ascii-reveal

Straight from GitHub (no npm publish needed):

npm i github:quanhoangindex/ascii-reveal

React 17 or newer is a peer dependency. The built files in dist/ are committed, so the GitHub install works without a build step.

Quick start

import { AsciiReveal } from 'ascii-reveal';

export function Page() { return ( https://github.com/quanhoangindex/ascii-reveal/blob/HEAD/

Hello world

Read more ); }

The content reveals when the component mounts.

Loading states

const { data, isLoading } = useQuery(...);

{data?.latency ?? '—'}

When loading turns true, the matching content scrambles out and a shimmer runs in its place. When it turns false, the new content decodes in.

Skeletons

Skeletons exist to paint instantly while data loads. AsciiSkeleton does exactly that, in ASCII. There are two ways to use it (live demo):

1. Skeleton only. A drop-in replacement for a gray skeleton. Content appears as normal when it arrives.

https://github.com/quanhoangindex/ascii-reveal/blob/HEAD/Three cards show ASCII dither skeletons, then the real content appears as each card's data arrives

import { AsciiSkeleton } from 'ascii-reveal';

{data ? : }

2. Skeleton + reveal. The skeleton paints first; when the data arrives, the real content decodes in (about 400 ms).

https://github.com/quanhoangindex/ascii-reveal/blob/HEAD/Three cards show ASCII dither skeletons, then the real content decodes in through a character grid

import { AsciiReveal, AsciiSkeleton } from 'ascii-reveal';

{data ? : }

The reveal never animates the skeleton itself. It leaves it alone while loading, and decodes the content that replaces it.

Pick a style with variant:

| variant | Look | | --- | --- | | dither (default) | Shaded blocks ░▒▓█ that read as soft bars, with a darker dither band scanning across. | | scan | Faint dots with a band of dense, scrambling glyphs. Matches the decode preset. | | braille | Fine braille dot texture; the band fills the dots in. | | terminal | Faint 0s and 1s, lit up in --ascii-accent as the band passes. |


{/ still pattern: cheapest, for long lists /}

Without React: el.innerHTML = asciiSkeletonHTML({ lines: 3 }), then animateSkeletons(el), both from ascii-reveal/core.

How much does it cost?

A skeleton only does its job if it shows up as fast as a gray box and never delays the data, so we measured it against one. Pre-rendered pages, no JavaScript needed to paint, Chromium on a machine without a GPU (so all drawing is done in software, the worst case), median of 7–11 runs:

| 12 cards, normal CPU | Gray skeleton | AsciiSkeleton | AsciiSkeleton animate={false} | | --- | --- | --- | --- | | First paint | 48 ms | 44 ms | 36 ms | | Style + layout at load | 2 ms | 9 ms | 5 ms | | Browser CPU while waiting | 15% | 21% | 0% | | HTML (gzipped) | 0.5 KB | 3.2 KB | 3 KB |

How it stays cheap:

Run it yourself: node scripts/skeleton-bench/build.cjs && node scripts/skeleton-bench/bench.cjs.

Server rendering

Content that arrives in server-rendered HTML is never hidden on hydration: it's already readable, so hiding it to animate it would make the page slower. Set revealOnHydrate if you want the effect anyway. Client-side navigations and loading transitions animate as usual.

Loading mascots

Swap the shimmer for an animated ASCII mascot while data loads. It dissolves as the new content decodes in.

https://github.com/quanhoangindex/ascii-reveal/blob/HEAD/A spider, a ghost and a pumpkin drawn in ASCII play while three cards load, then dissolve as the content decodes in

  {/ spider | ghost | pumpkin | bat /}

… {/ your own SVG /}

Pass an SVG URL, SVG markup, or a draw function (ctx, w, h, t, color) => void for full control. Set --ascii-mascot to change the color of the line-art mascots.

Replay from code

const ref = useRef(null);

…

// replay one card from where it was clicked ref.current?.reveal({ within: cardElement, origin: { x: e.clientX, y: e.clientY } }); ref.current?.hide();

Props

| Prop | Type | Default | What it does | | --- | --- | --- | --- | | preset | 'decode' \| 'dither' \| 'terminal' \| 'blueprint' \| Preset | 'decode' | Glyph set, timing and image style. | | duration | 'fast' \| 'cinematic' | 'fast' | fast makes data readable in ~400 ms. cinematic is the slower, showier wave for hero sections. | | speed | number | 1 | Playback speed multiplier on top of duration. | | origin | 'center' \| 'top-left' \| 'pointer' \| { x, y } | 'center' | Where the wave starts. { x, y } is in viewport pixels. | | selector | string | – | Only animate content inside elements matching this selector. | | revealOnMount | boolean | true | Reveal when the component mounts. | | loading | boolean | – | Scramble out and shimmer while true; decode in when it turns false. | | shimmer | boolean | true | Show the glyph shimmer while loading. | | lazy | boolean | true | Sections below the fold decode as they scroll into view instead of all at once. | | revealOnHydrate | boolean | false | Also animate content that was server-rendered. | | fallback | boolean | true | If frames take too long, finish the animation and use a short fade for the next 10 s. | | mascot | 'spider' \| 'ghost' \| 'pumpkin' \| 'bat' \| string \| MascotDraw | – | Animated ASCII mascot instead of the shimmer while loading. | | onRevealComplete | () => void | – | Called when a reveal finishes. | | as | ElementType | 'div' | Element used for the wrapper. |

All other props pass through to the wrapper element.

Marking elements

| Attribute | Effect | | --- | --- | | data-ascii="surface" | Cards and panels. A dot field and corner frame appear first, then the surface fades in. | | data-ascii="fade" | Buttons, chips, badges. Fades in on the wave. | | data-ascii="media" | Treat any element as media (rendered as a glyph texture). | | data-ascii="skip" | Leave this subtree alone, for example a toolbar that must stay usable. | | data-ascii-digits | Scramble only through digits (applied automatically to numeric text). |

Theming

The effect reads these CSS custom properties from the wrapper:

.my-app {
  --ascii-accent: #5b8cff;   / cursor and blueprint glyphs /
  --ascii-skeleton: #888;    / AsciiSkeleton glyph color (defaults to the text color) /
  --ascii-flash: #5b8cff;    / optional: brief color as each character lands /
  --ascii-glyph: #888;       / scramble glyph color (defaults to the text's own color at 50%) /
  --ascii-font: "Geist Mono", ui-monospace, monospace;
  --ascii-surface: #0b0b0d;  / color behind transparent images, if detection is wrong /
}

Without React

import { createAsciiReveal } from 'ascii-reveal/core';

const reveal = createAsciiReveal(document.querySelector('#app')!, { preset: 'dither' }); reveal.reveal(); // later await reveal.hide(); reveal.shimmer(true);

Presets

Make your own by passing an object with the Preset shape (ramp, scramble, mode, color, cells, tick).

Performance

Measured on the demo page with Playwright and Chromium, CPU throttled 4×, on a machine with no GPU (so every frame is drawn in software, which caps even the idle page at ~19 fps). Run it yourself with scripts/bench.cjs (instructions at the top of the file).

| | v0.2 | v0.3 | | --- | --- | --- | | Frame rate during Replay (page idle rate in brackets) | 8.4 fps (12.5) | 16.6 fps (19) | | 95th percentile frame | 372 ms | 133 ms | | Longest main-thread task | 297 ms | 174 ms | | Data readable after it arrives | ~920 ms | ~350 ms |

Without throttling, v0.3 Replay runs at the page's idle frame rate and the longest task drops from 68 ms to under 20 ms. Note that v0.3's demo also replays only the card grid rather than the whole page.

What changed:

Notes

Develop

npm install
npm run build        # builds dist/
npm test             # browser smoke test (npx playwright install chromium first)
npm run demo         # runs the demo site (cd demo && npm install first)

See CHANGELOG.md for what changed between versions.

License

MIT

GitHub Stars & Activity

550Stars
47Forks
0Open issues
TypeScriptLanguage

GitHub Popularity

GitHub stars550
Forks47
Open issues0
Primary languageTypeScript
License-
Stars gained today0
Created-
Last pushed-

Trending History

Weekly boardrank #54 · ▲ 0 stars

Related GitHub Projects

1

andyhuo520 / digital-human-koubo

TypeScript★ 1,400⑂ 323
→
2

kargulstudio / calender-app-design

TypeScript★ 795⑂ 96
→
3

yaojingang / GEOInflow

TypeScript★ 707⑂ 227
→
4

blakeandersonw / ai-app-playbook

TypeScript★ 571⑂ 77
→
5
→
6

shipwords-dev / shipwords

TypeScript★ 237⑂ 152
→
7

D3voz / openjutsu

TypeScript★ 226⑂ 41
→
8

rudderlabs / devbox

TypeScript★ 160⑂ 9
→

More Trending Repositories