Power-User Systems

Ascii Engine

A lit, raymarched 3D solid rendered at exactly one pixel per character cell, then quantised into a glyph ramp drawn once with fillText. Drag to orbit it through a full three-sixty. Real geometry underneath, terminal on top — and no scene graph, no mesh, and no second library to get there.

Install

bun add ogl

Then copy 2 files into your project:

  • components/registry/ascii-engine/ascii-engine.tsx
  • hooks/use-animation-loop.ts

Props

PropTypeDefaultDescription
solid"torus-knot" | "cube" | "sphere" | "gyroid" | "column""torus-knot"Which distance field is raymarched into the first pass. A field rather than a mesh: the silhouette stays exact at any cell size because it is evaluated instead of rasterised, which is why this needs no scene graph and no geometry upload.
charset"classic" | "blocks" | "minimal" | "binary" | "dots""classic"The glyph ramp, darkest to lightest. The atlas is drawn once with fillText into an offscreen canvas and uploaded as a single texture, so the shader just indexes it and a longer ramp costs nothing per frame.
cellSizenumber10Width of one character cell, and the real resolution control. The first pass renders at exactly one texel per cell, so halving this quadruples the raymarch and changes nothing else — which makes it the honest performance dial rather than a cosmetic one.
spinSpeednumber0.35Rotation speed of the solid. At zero it parks, which is the only way to judge whether the ramp is actually resolving the form or just flickering convincingly.
tiltnumber0.4Resting camera elevation. Dragging orbits from here rather than replacing it, so this control still means something after you have spun the solid around — and the pitch is clamped short of the poles, because a camera that rolls over the top reads as a bug rather than as a rotation you asked for.
zoomnumber1How much of the frame the solid fills. It narrows the field of view rather than moving the camera in — dollying would clip the near face of the solid long before its silhouette filled the frame, which looks like a broken near plane rather than a close-up.
contrastnumber1.1Gamma on the luminance before it picks a glyph, and what decides whether the solid reads as a form or as noise. The ramp has ten steps at most and the lighting has to spread across all of them — too little and the shape collapses into two characters.
edgeBoostnumber0.5How much of the silhouette is added back before quantising. Pure luminance loses the outline — a ten-step ramp cannot carry both the shading and the contour, so without this the form dissolves into its own gradient.
glownumber0.3Bloom bleeding off the lit glyphs, driven by the cell's luminance rather than by the glyph's own coverage — so a bright cell glows whether it landed on a full block or a full stop.
inkColorstring (hex)"#7ef0c0"The phosphor the glyphs are printed in.
backgroundColorstring (hex)"#04060a"The dead terminal behind them.

What It Demonstrates

Loop
An animation that repeats, a set number of times or infinitely.
Rotate
Spin an element around a point.
Drag
Moving an element by grabbing it, often with momentum when released.
Momentum
Motion that carries velocity, especially after a drag or interruption.
Stepped animation
An animation that is divided into discrete steps, like a countdown timer.
Idle animation
Subtle motion that plays while an element is just sitting there, waiting to be interacted with.
Compositing
Letting the GPU move or fade an element on its own layer without redoing layout or paint.

Related Components

Appears In