Asciipaper
asciipaper engine
A small GPU renderer that turns one GLSL function into animated ASCII art, and gives it back to you as a live wallpaper, a page background, a looping video, a GIF or a still.
It is built to be driven by an agent (or by hand): write vec4 cell(vec2 uv), render a
frame to look at it, change something, render again, export when it is right.
vec4 cell(vec2 uv) {
float glow = smoothstep(0.5, 0.0, length(uv - vec2(0.5)));
return vec4(vec3(0.55, 0.9, 0.84) * glow, glow); // rgb = ink, a = brightness
}The engine runs that once per character cell, maps brightness to a glyph from a ramp and draws every cell with its own colour. Per frame the CPU only sets uniforms, so a whole screen of characters costs about as much as one full-screen quad.
ASCII Paper is the app built on this engine (Studio, Discover packs, community, Windows / Linux / macOS / Android apps).
What you can make with it
Result | How |
live wallpaper on a Wayland desktop |
|
still image, any resolution |
|
video or GIF |
|
background inside a web page | a |
a shareable wallpaper file | the same JSON spec, on any platform |
Related MCP server: ASCII Motion MCP
For agents
The loop is four commands. Nothing needs a server, an account or a network.
# 1. a wallpaper is one JSON file and one shader (start from an example)
cp wallpapers/specs/plasma.json my-wallpaper.json
cp wallpapers/specs/plasma.glsl my-wallpaper.glsl
# 2. render a frame and look at it (--seconds picks the moment, so it is repeatable)
./native/asciipaper-engine --spec my-wallpaper.json --lib wallpapers/lib \
--snapshot try-1.png --size 1280x720 --seconds 4
# 3. change the shader or the look, render try-2.png, compare, repeat
# 4. export: a still, a clip, or ship the JSON to a page
./native/asciipaper-engine --spec my-wallpaper.json --lib wallpapers/lib \
--snapshot poster.png --size 3840x2160 --seconds 6Rules that keep renders honest:
Deterministic frames.
--seconds Nsimulates exactly N seconds of the scene, so the same spec always gives the same frame.--pointer X,Ysimulates the pointer.No hidden state. The spec declares everything: glyphs, cell size, colours, dither, palette, effects, interaction.
wallpapers/lib/looks.jsonlists every name you may use.Two renderers, one language. The C engine and the WebGL runtime run the same shaders and specs, so a wallpaper previewed in a browser is pixel-compatible on a desktop.
A prompt that works:
Write an asciipaper wallpaper: a JSON spec plus a GLSL
vec4 cell(vec2 uv)returning colour and a 0..1 brightness, usingu_time,u_aspect,u_pointerandu_clicks. Run./native/asciipaper-engine --spec wallpaper.json --lib wallpapers/lib --snapshot frame.png --seconds 4, look at the frame, and iterate until it reads well at 1280×720 withcell: 8. Export a still when it is done.
Read next: the spec and uniform reference below, llms.txt, and the three examples in
wallpapers/specs/.
Two renderers, one language
What it is | Where it runs | |
| C, OpenGL ES, Wayland layer-shell | Linux desktops: behind your icons, on every monitor; PNG and video export |
| the same renderer in WebGL 1 | any browser, and the Windows / macOS / Android hosts |
native/shaders.h and wallpapers/lib/shaders/ are generated from the web runtime by
tools/generate_runtime.py, so the two sides cannot drift apart.
Build
make # the native engine, into native/asciipaper-engine
make test # spec + shader checks (needs python3 and glslangValidator)Build deps: a C compiler, pkg-config, libwayland-client, libwayland-egl, libegl,
libgles2, pangocairo, wayland-scanner and wayland-protocols.
Run it
./native/asciipaper-engine plasma # live, on every Wayland output
python3 -m http.server -d wallpapers 8000 # then /run.html?spec=specs/plasma.jsonUseful flags: --spec FILE, --lib DIR (where media.glsl lives), --snapshot OUT.png,
--size WxH, --seconds S, --pointer X,Y, --record FPS, --warmup S, --headless.
A wallpaper is a JSON file plus a shader
{
"title": "Plasma",
"shader": "plasma.glsl",
"charset": " .:-=+*#%@",
"cell": 9,
"aspect": 0.55,
"fill": 0.2,
"background": "#050507"
}Everything a look can have is a key in the same file: shape (pixels, dots, LEGO, CMYK,
truchet, hex…), dither (ordered patterns), palette (nearest-colour inks), effects
({"crt": 1}, scanlines, bloom, glitch, grain, posterize, vhs…), interaction (glow,
magnify, repel, attract, swirl, ripple), speed, pace, weight, maxCells,
font, color. The names and ranges are all in wallpapers/lib/looks.json.
A shader may declare its own defaults on the first line, overridable per spec:
// defaults: {"speed": 1, "tint": "#8de5d7"}
uniform float speed;
uniform vec3 tint;cell(uv) gets:
uniform | meaning |
| seconds, scaled by the speed setting |
| width / height |
| cells across, cells down |
| output size in pixels |
| pointer, 0..1 |
| recent clicks as |
| RGBA image, for CPU-driven or imported-media scenes |
Return vec4(rgb, level): level (0..1) picks the glyph, rgb is that cell's ink. Shaders
are GLSL ES 1.0, so they run unchanged on the native and the web side.
In a web page
Give the runtime a canvas and it sizes the cells to that box (wallpapers/embed.html is a
working page):
<canvas id="art" style="width:100%;height:420px;display:block"></canvas>
<script src="asciipaper.js"></script>
<script>
asciipaper.ascii({
canvas: document.getElementById('art'),
charset: ' .:-=+*#%@', cell: 8, aspect: .55, background: '#050708',
glsl: `vec4 cell(vec2 uv){
float l = .5 + .5 * sin(u_time + length(uv - .5) * 12.0);
return vec4(vec3(.6,.9,.85) * l, l);
}`
});
</script>Or run a whole spec file: asciipaper.load('wallpapers/plasma.json').
The runtime API: ascii(config), load(url), patch(url) (apply uniform-only edits to a
running scene), set(options) (fps, idleFps, quality, speed, pointer, paused), capture(),
beat (timestamp of the last drawn frame).
Credits
MIT, see LICENSE. The fluid scene is a 1:1 port of asciify
(MIT, licenses/asciify-engine-MIT.txt). The look tables were inspired by ASCII Magic;
every shader and line of code here is written for this engine.
This server cannot be deployed
Maintenance
Related MCP Connectors
Draft, validate, render, and share split-flap and flip-dot board videos written in flipcode.
Generate pixel art sprites, animations, 8-direction rotations and palettes for games.
Deterministic procedural SVG/PNG backgrounds: 58 generators, curated palettes, brand kits.
Make animated videos by asking Claude, Cursor or any MCP client. Your AI writes it, we render it.
Related MCP Servers
- AlicenseAqualityCmaintenanceASCII art & kaomoji for AI agents, CLI tools, and chatbots.1126 npm1MIT
- AlicenseBqualityAmaintenanceEnables AI assistants to create, animate, and export ASCII art using natural language, with live browser sync.96584 npm12MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI to create ASCII and SVG art through a character canvas, with tools for drawing, previewing, and exporting to multiple formats, as well as composing stop-motion animations with optional voice-over.MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to create loop-perfect generative ASCII animations headlessly, including defining custom animations and 3D shapes as expression strings.22 npmMIT