ascii-texture-grounds

Generated source view for the actual executable engineering/ascii-texture-grounds skill. The durable routing article is Security and Review Skills. Source: skills/engineering/ascii-texture-grounds/SKILL.md

Runtime Source

Field Value
Category engineering
Origin personal
Slug ascii-texture-grounds
Source slug ascii-texture-grounds
Family Security and Review Skills
Source skills/engineering/ascii-texture-grounds/SKILL.md

Bundled Resources

No bundled resource files.

Description

Build full-bleed interactive grounds from glyphs, dither cells or word tiles that hold 60 fps and cost nothing idle: ASCII fields, logo reveal fields, Bayer and halftone dither, tile walls. Use when a page needs a signature background or texture.

Skill Source

---
name: ascii-texture-grounds
description: >-
  Build full-bleed interactive grounds from glyphs, dither cells or word tiles that hold 60 fps
  and cost nothing idle: ASCII fields, logo reveal fields, Bayer and halftone dither, tile walls.
  Use when a page needs a signature background or texture.
origin: personal
source_slug: ascii-texture-grounds
---

# ASCII and texture grounds

A ground is the full-bleed surface behind a page's type. Done well it is the page's one signature idea (`less-is-more-web` section 3): it shows the product's own material and answers the pointer. Done badly it is decoration that costs a frame budget.

References Kevin pointed at (2026-10-30): logo cards whose marks are built from vertical glyph strokes with a "Reveal the source" interaction and editor-style selection boxes with coordinates; a wall of colored word tiles assembling on a loop from a vocabulary; textures.dev, a library of hover-reactive brand textures shipped as one component each.

## 1. Pick the material, then the form

The field must be made of something true about the product. Choose the material first:

| Material | Example |
| --- | --- |
| The product's vocabulary | action names, commands, block types, keyboard shortcuts |
| The product's data | a document's source text, coordinates, numbers from the real system |
| The product's marks | the logo, the brand cells, a recurring glyph |
| A real picture | a photograph or slide rendered through the product's own dither |

Then pick the form:

| Form | How it reads |
| --- | --- |
| Density field | each cell's glyph or stroke weight follows the luminance of a source image |
| Reveal field | the field renders a picture; the pointer lifts a lens or a selection box that shows the source underneath |
| Tile wall | words from the vocabulary set in colored blocks, flowing or assembling |
| Dither ground | Bayer 8x8 or blue-noise threshold of a picture into two tones |

Combine at most two. A density field with a reveal lens is a strong default for a product whose output is generated from source.

## 2. The drawing recipe

- **One canvas per ground**, sized to its box with CSS and to `devicePixelRatio` (capped at 2) for its backing store. Use 2D canvas for up to a few thousand cells; use WebGL with an instanced quad per cell when cells exceed about 20,000 or every cell changes every frame.
- **Prebuild a glyph atlas** once after the font loads: draw each glyph of the ramp into an offscreen canvas (or `OffscreenCanvas` in a worker) and blit with `drawImage` from the atlas. Never call `fillText` per cell per frame.
- **Sample the source once.** Decode the source image into a luminance grid at the cell resolution and keep it. Recompute only on resize, never per frame.
- **Draw only what changed.** Keep the last drawn glyph index per cell and repaint dirty cells. A pointer lens dirties a small disc, not the whole field.
- **Animate on demand.** Run `requestAnimationFrame` only while something moves (the pointer, a settling spring, the one loop the page owns). Stop the loop when the field is at rest.
- **Pause off screen and when hidden.** `IntersectionObserver` and `visibilitychange` stop the loop.
- **Paint a still first frame.** The server renders a static image or CSS gradient of the same field (or the canvas draws synchronously on mount from data already in the bundle) so the first screen is complete before any animation. Reserve the box size in CSS so nothing shifts.
- **Respect reduced motion.** With `prefers-reduced-motion: reduce` draw one still frame and keep pointer reveal (it is input-driven), but drop any loop.
- **Theme by tokens.** Read ink and paper from CSS custom properties at draw time so light and dark both work, and redraw on theme change.

## 3. Glyph ramps that look good

- Use the page's own monospace face for ASCII. Measure its advance width once and size cells from it, so the field aligns with any code on the page.
- A density ramp of 8 to 12 glyphs ordered by ink coverage reads better than 70. Measure coverage from the atlas and sort; do not trust a published ramp for a new face.
- Vertical strokes (`|`, `¦`, `│`, or a custom stroke-height ramp) give the barcode logo look. Vary height or weight per cell, not glyph identity.
- Keep contrast moderate. The ground sits behind type; headline text must pass contrast against the ground's darkest region, so dim the field under text with a radial or rectangular falloff.

## 4. Interaction patterns

- **Reveal lens.** Inside a radius around the pointer, cells switch from density glyphs to source text (the commands or data that made the picture). Ease the radius with a spring.
- **Selection reveal.** Snap a selection box to the nearest object under the pointer and label it with real coordinates and a name, in the product's own selection style.
- **Scrub.** Horizontal pointer or scroll position scrubs time in the field's one animation.
- **Tile pick.** Hovering a tile in a word wall shows what the word does in one sentence; clicking runs or links it.
- On touch, map the lens to the touch point while dragging and leave a still state when idle. Never block page scrolling on touch.

## 5. Accessibility and agent experience

- The canvas gets `role="img"` and an `aria-label` describing what it shows, or `aria-hidden="true"` when the same content exists as text on the page.
- Any word, command or number the field reveals also exists as real text somewhere accessible.
- Pointer-only reveals have a keyboard path (focusable objects, arrow keys) when they carry information.

## 6. Budget and checks

- Script for the ground: under 15 KB minified and gzipped, no dependencies.
- Idle CPU: zero frames scheduled when nothing moves (check with the Performance panel or a `requestAnimationFrame` counter).
- Interacting: 60 frames a second at 1440 by 900 on a laptop, frame time under 8 ms.
- Layout shift: 0 from the ground.
- Check light, dark, reduced motion, 390 wide and a high-DPR screen.

Timeline

1 page links here