Skip to content

mapscii — Braille/ASCII Terminal Map Renderer

  • Source: https://github.com/rastapasta/mapscii
  • Category: tech / effect — vector-tile → Braille/ASCII renderer with a pannable/zoomable spatial canvas
  • Role for KN-86: the braille-density rendering reference — the companion to browsh’s half-block technique. Where half-block gives 2× vertical resolution and clean filled regions, mapscii’s braille path gives a 2×4 sub-cell dot grid for fine, sparse detail (lines, contours, scatter), and demonstrates pan/zoom spatial navigation with label placement on a text grid.

Batch 8 (readers / browsers / hierarchical-navigation TUIs).

mapscii is a Node.js “Vector Tile to Braille and ASCII renderer for xterm-compatible terminals.” It fetches vector map tiles (OSM2VectorTiles or a custom server), parses them (vector-tile + pbf), applies style rules, triangulates/simplifies geometry (earcut, polyline simplification), and rasterizes the result into terminal glyphs — braille patterns by default, with a block-character mode toggle. It’s fully interactive: drag to pan, scroll-wheel to zoom (a/z also zoom), c toggles block-character mode, q quits, and it discovers and labels points-of-interest around a location.

  • Braille density rendering is the second pillar of KN-86’s single-color pixel toolkit (half-block being the first — see browsh). It is monochrome-native: braille dots are on or off, carrying no color, which is exactly KN-86’s amber-on-black constraint.
  • Spatial canvas with pan/zoom. A bounded viewport over an unbounded coordinate space, panned by drag/keys and zoomed by level, is a reusable KN-86 pattern: any cart with a map, a star-field, a node-graph, or a large schematic gets the same viewport-over-world navigation. On KN-86 (no mouse on the device per Canonical Hardware Specification) this is keyboard pan (arrows/HJKL) + zoom keys — mapscii already supports the keyboard path (arrows, a/z).
  • Label placement on a glyph grid. mapscii places POI text labels over the rendered geometry. Drawing readable text labels atop a dense glyph canvas — without the label and the canvas colliding into mush — is a real KN-86 problem for any annotated-graphic surface; mapscii is a working reference.
  • Render-mode toggle (c). mapscii lets the user switch braille ↔ block characters at runtime. KN-86 should treat its pixel-encoding modes (half-block vs braille vs solid block) as a selectable render mode the same way, chosen by content and legibility — fine sparse geometry → braille; filled regions/photos → half-block.

mapscii’s braille path is already pure monochrome — this is the adaptation, and the dot-bitmask math (from mapscii’s BrailleBuffer source) is the lift-ready primitive for KN-86:

The braille mechanism. Each character cell is a 2×4 grid of dots (2 wide, 4 tall) mapped to a single Unicode braille glyph. The codepoint is 0x2800 + bitmask, where the bitmask packs eight on/off dots. mapscii’s dot-position map is:

brailleMap = [[0x01, 0x08], // row 0: col0=0x01 col1=0x08
[0x02, 0x10], // row 1: col0=0x02 col1=0x10
[0x04, 0x20], // row 2: col0=0x04 col1=0x20
[0x40, 0x80]]; // row 3: col0=0x40 col1=0x80

Setting a sub-pixel is pixelBuffer[idx] |= mask (dots accumulate by OR), and the cell index projects 2D coords as (x>>1) + width_in_cells*(y>>2) — i.e. each cell owns 2 horizontal × 4 vertical source pixels. The glyph is then String.fromCharCode(0x2800 + pixelBuffer[idx]). This gives a 2×4-per-cell monochrome pixel canvas — finer than half-block’s 1×2, ideal for thin lines, contours, and sparse scatter where you want maximum spatial resolution from the grid.

Block-character fallback. When braille is off, mapscii maps the same accumulated bitmask to the closest block glyph (█ ▀ ▄ and friends) by coverage. This is the same four-glyph half-block set documented in the browsh entry — so the two techniques share an output vocabulary and can be driven from one accumulation buffer, just rendered through different glyph tables.

KN-86 guidance: carry both in the render toolkit. Braille (2×4) for fine sparse geometry and dense data plots — and it’s the same primitive netwatch wants for sparklines/heatmaps on CIPHER-LINE. Half-block (1×2, four-glyph) for filled regions and image-like content. Both are monochrome by construction; amber intensity (where the cell carries it) grades brightness without leaving the palette.

  • Node.js is not an on-device path — the Pi Zero 2 W won’t run mapscii’s stack, and KN-86 ships no live tile data. The value is the braille-dot bitmask primitive, the pan/zoom viewport pattern, and label-on-glyph-canvas placement, studied as reference and reimplemented in C.
  • Cross-link browsh — the half-block sibling; together they define KN-86’s two-mode glyph pixel toolkit (1×2 filled vs 2×4 sparse).
  • Cross-link ascii-effects.md — the project-wide character-rendering spec; braille belongs in its render-mode roster alongside half-block.
  • Cross-link libcaca.md — the raster-image→glyph engine reference; libcaca handles image quantization/dithering, mapscii handles vector-geometry→braille. Different inputs, shared “pixels into glyphs” output.
  • Cross-link netwatch — wants braille for inline sparklines/heatmaps on the data view and CIPHER-LINE; mapscii is the rendering reference for that.
  • Cross-link asciinator (Batch 3) — the halfblock- technique foundation that the block-character fallback here shares.