Chinese Dragon TUI

August 10, 2026 · View on GitHub

A self-contained, true-color terminal artwork: a complete Chinese dragon rendered from square-pixel RLE data.

Chinese dragon pixel preview

Run

Requirements: Node.js 18+ and a terminal with 24-bit color support.

git clone https://github.com/x0c/chinese-dragon-tui.git
cd chinese-dragon-tui
./dragon-tui

The app enters the alternate terminal screen, scales the artwork to the current terminal while keeping the whole dragon visible, and compensates for terminal character geometry with a 1.25× horizontal correction. Press q or Esc to exit.

Useful commands:

./dragon-tui --status
./dragon-tui --json
./dragon-tui --render

Data format

dragon-grid.json uses `tui-square-grid-rle/v1$:

  • 256 \times 170 \text{logical} \text{square} \text{cells}
  • 64-\text{color} \text{true}-\text{color} \text{palette}
  • \text{row}-\text{based} \text{run}-\text{length} \text{encoding}, \text{where} \text{each} \text{run} \text{is} $[paletteIndex, length]`
  • background palette index: 0 (#FFFFFF)

The renderer packs two adjacent logical rows into one character, using the foreground color for the upper cell and background color for the lower cell. This makes the full source render in 256 terminal columns × 85 rows before responsive scaling.

From pixel art to terminal grid data

The project includes both the input artwork (source-dragon.png) and the converter (make_tui_dragon_grid.py), so the data is reproducible instead of being a hand-written approximation.

python3 -m pip install Pillow
python3 make_tui_dragon_grid.py source-dragon.png \
  --output dragon-grid.json \
  --preview dragon-grid-preview.png

The converter performs these steps:

  1. Nearest-neighbor sampling — it downsamples the 1536 × 1024 pixel artwork to a 256 × 170 logical grid. Nearest-neighbor sampling is intentional: averaging would blur the hard edges of pixel art.
  2. Separate the white backdrop — any nearly white cell (R, G, and B all at least 244) becomes palette index 0, fixed as #FFFFFF. This prevents the empty background from consuming palette slots.
  3. Preserve the dragon palette — all foreground cells are median-cut quantized into 63 colors, then combined with the white background to form a 64-color true-color palette. Keeping the palette budget for the foreground retains the small color transitions in the head, scales, and claws.
  4. Encode every row with RLE — adjacent cells using the same palette index become [index, count] runs. The JSON therefore remains compact while decoding back to exactly 256 cells per row.
  5. Render square logical cells in a terminaldragon-tui.mjs decodes the RLE and combines two neighboring logical rows into the Unicode character. Its foreground color draws the upper cell and its background color draws the lower cell. A 1.25× horizontal correction compensates for how terminal glyphs look on screen.

The generated dragon-grid-preview.png is a nearest-neighbor enlargement decoded from the JSON itself. It is the visual check that the generated data, rather than the source image alone, still contains the complete dragon.

License

MIT