Flip-dot Letter & Image Playground
An interactive text-to-flipdots animated SVG generator and electromechanical display board for Markdown profiles, websites, and terminal environments.
Live playground: https://flip.taruna.me
FLIP simulates modular electromechanical flip-dot display boards mounted inside an anodized aluminum bezel. Letters and punctuation transition through rotating phrases using electromagnetic diagonal sweep waves, highlighting active amber solenoids and resting in a recessed dark zero-state.
SVGs produced by the engine are completely standalone with pure inline CSS keyframe animations. They require no JavaScript, external font files, or remote stylesheets, making them safe for GitHub README profiles, Camo proxies, and static documentation.
- Converts multi-line custom messages into rotating animated SVG banners with zero client-side dependencies.
- Rasterizes animations server-side into smooth 24 FPS WebP and APNG formats with duplicate frame compression.
- Generates settled still frames for each phrase, allowing direct export of static vector SVGs or high-resolution PNG snapshots.
- Serves exact-dimension responsive placeholders with short cache headers during cold raster generation to prevent GitHub Camo timeouts.
- Bundles complete frame sequences into downloadable ZIP archives directly within the browser using JSZip.
- Includes five color presets: Amber Solenoid, Emerald Transit, Monochrome White, Cyber Cyan, and Crimson Hazard.
- Supports forward 24-degree italic shear and upright typography, round or square dot geometries, and left, center, or right text alignment on a wider board.
- Supports per-frame
$[key=value, ...]display overrides, including independent text color and board background settings. - Features real-time stage telemetry, configurable dot pitch, duration controls, text alignment, and multiple stage backdrop themes (Dark, Light, Grid).
- Provides a standalone CLI utility for headless SVG generation and ASCII terminal matrix rendering.
- Exposes a Fastify HTTP service for dynamic on-demand SVG, WebP, and APNG generation via query parameters.
You can reference the live API endpoint directly in any Markdown document or GitHub profile:
Which results in:
To render static non-animated frames, use the /api/frame endpoint:
Which results in:
Append $[key=value, ...] to a phrase to change its display settings for that frame. Commas inside the brackets separate settings; commas outside them separate frames.
For example:
hello $[color=amber, background=#10141d, align=left]
world $[color=cyan, background=emerald, shape=square, italic=false, duration=2.5, pitch=16]
bye $[theme=crimson, align=right]
The lines play in order, and each frame's settings apply only while that frame is displayed. Read the example like this:
- First,
helloappears with amber dots on a custom dark background, aligned to the left. - Next,
worldappears with cyan dots on an emerald board. Its dots are square, its text is upright, it stays up for 2.5 seconds, and its pitch is 16 pixels. - Finally,
byeappears with the crimson palette for both dots and background, aligned to the right.
Any setting omitted from a frame keeps the board's default value.
You can set these options inside $[...], the option keys match the HTTP API query parameters (see API reference). While most options are customizable per-frame, renderTech is not, and can only be applied to board-wide rendering.
When embedding in environments that do not support animated vector SVGs, you can request 24 FPS animated WebP or APNG outputs by setting format=webp or format=apng:
<!-- 24 FPS animated WebP -->

<!-- Animated PNG -->
Generating a multi-phrase 24 FPS animation takes several seconds of deterministic frame sampling. GitHub routes external media through its Camo proxy (camo.githubusercontent.com), which terminates origin requests taking longer than 10 seconds.
To ensure links never time out on GitHub:
- First load (cache miss): The server immediately returns an exact-dimension placeholder image (
GENERATING FLIP-DOT ANIMATION... Please wait for a moment - Reload from time to time to view) withCache-Control: public, max-age=4, s-maxage=4, must-revalidate. Because the placeholder matches the exact board dimensions, Cumulative Layout Shift is zero (CLS = 0). - Background rendering: The server compiles and caches the 24 FPS raster output in the background.
- Subsequent reloads (cache hit): Once rendering finishes, Camo revalidates with the origin and caches the complete animation with a standard duration (
max-age=60, s-maxage=300).
To inspect the placeholder styling and dimensions during development without triggering an actual background render, open the dedicated developer preview page at /preview-placeholder or request:
GET /api/placeholder?width=1260&height=234&theme=amber&format=webp
The Fastify HTTP service exposes /api/svg and /api/frame with these query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
texts |
string |
(preset) | Comma-separated list of phrases to cycle through. |
text |
string |
Single text phrase (alternative to texts). |
|
format |
string |
svg |
Target output format: svg, webp, or apng. |
shape |
string |
circle |
Dot geometry: circle (round) or square. |
theme |
string |
amber |
Combined text-color and board-background palette: amber, emerald, white, cyan, or crimson. |
color |
string |
theme |
Active dot/text color. Accepts a palette name or hex color. |
background |
string |
theme |
Board background palette or hex color. |
shape |
string |
circle |
Dot geometry: circle (round) or square. |
italic |
boolean |
true |
Forward slant typography (true for 24-degree slant, false for upright). |
align |
string |
center |
Horizontal text alignment on the board: left, center, or right. |
duration |
number |
3.8 |
Display dwell time per message in seconds. |
pitch |
number |
14 |
Dot center-to-center pitch in pixels. |
dotSize |
number |
pitch - 2 |
Flip-dot diameter or square width in pixels. |
dotRadius |
number |
2.2 |
Corner radius for square dots. |
letterSpacing |
number |
2 |
Horizontal spacing between adjacent glyphs, in matrix columns. |
wordSpacing |
number |
5 |
Width of spaces between words, in matrix columns. |
padX / padY |
number |
3 / 2 |
Horizontal and vertical matrix padding. |
rows / minCols |
number |
13 / 86 |
Minimum matrix dimensions in rows and columns. |
flipDuration |
number |
0.35 |
Flip transition duration in seconds. |
sweepMax |
number |
0.85 |
Maximum sweep delay in seconds. |
renderTech |
string |
compound-path |
Board-wide SVG rendering method: compound-path (compact) or original (individual elements). |
sync |
boolean |
false |
When true, synchronously waits for rasterization to finish instead of returning a placeholder. |
frame |
number |
0 |
Zero-based frame index for static exports via /api/frame. |
Generate an animated SVG banner or preview matrix layouts directly in your terminal:
# Generate a banner from rotating text phrases
pnpm generate -t "hello world" -o assets/banner.svg
# Choose text alignment, color, and background
node dist/cli.js --texts="short $[align=right],a much longer phrase" --align=center --color=cyan --background=amber
# Output ASCII preview of dot matrix layouts in the console
node dist/cli.js --texts="hello,world" --preview-asciiBuild the static client SPA, Fastify server bundle, and standalone CLI into dist/:
pnpm buildStart the production server:
pnpm startThe server listens on http://0.0.0.0:4329, serving the static client application alongside the dynamic /api endpoints.
Build and run the rootless production container:
docker build -t local/flip:0.2.0 .
docker run -d --name flip -p 4329:4329 local/flip:0.2.0The project requires Node.js >= 22.18 (or Node 24) and pnpm.
Install project dependencies:
pnpm installRun the development environment:
# Start Fastify API backend in watch mode (port 3029)
pnpm dev:api
# Start Vite React frontend with HMR (port 4329, proxying /api to 3029)
pnpm devOpen http://localhost:4329 in your browser to inspect the playground.
Run unit tests, type checking, and style linters:
# Run Vitest unit tests
pnpm test
# Run TypeScript type check
pnpm typecheck
# Run Biome and ESLint checks
pnpm check
# Automatically format code
pnpm formatMIT License. Copyright (c) 2026 Taruna Prasetya.