---
title: Meet PaTUI: MS Paint for the Terminal, with Vim Controls
author: George Mandis <george@mand.is>
date: 2026-05-06
description: A terminal-based image editor with Vim-style modal controls, retro palette filters, and Floyd-Steinberg dithering. Built with Bun, React, and Ink.
tags: post, programming, cli, recurse-center
---

<!--
  TONE: The tagline does the heavy lifting. This post is about the joy of
  building something delightfully useless and the surprising depth of
  the terminal as a creative medium. Keep it light.

  TARGET LENGTH: 800-1200 words (shorter than the others -- this is a
  "look at this fun thing" post, not a deep dive)

  ARC: tagline -> what it is -> show it -> the fun parts -> why terminal ->
       how it works (brief) -> try it

  HN HOOK: The tagline. "The elegance of MS Paint meets the user-friendliness
  of Vim wrapped in the performance of JavaScript."

  REPO: https://github.com/georgemandis/patui
-->

<!--
  The tagline IS the opening. Don't add preamble before it.
  Then immediately show what it actually does.
-->

Every once in a while, a revolutionary product comes along that changes everything.  One is very fortunate if they get to work on even *one* of these in their career.

Today I'm proud to introduce three revolutionary products of this caliber. The first is a state-of-the-art image editor channeling the elegance of MS Paint. The second is an unparalleled user-interface experience continuing the long-standing, intuitive traditions of Vim. And the third is software leveraging the blazingly performant, brilliantly designed programming language that is JavaScript.

So that's three things: an image editor in the class of MS Paint. An unimaginably intuitive user-interface paradigm rivaling Vim. A software product finally realizing the raw horsepower and sensible typing decisions of JavaScript.

<!-- MS Paint. Vim. JavaScript. -->

*MS Paint. Vim. JavaScript.*

Are you getting it?

![The PaTUI screen with an image of the author's face loaded](https://georgemandis.s3-us-west-1.amazonaws.com/patui/patui-screenshot-me.png)

These are not three separate products. This is *one* product, and we're calling it **PaTUI**.

![The PaTUI screen with the word PaTUI drawn in a pixel-art-meets-Comic-Sans style logo](https://georgemandis.s3-us-west-1.amazonaws.com/patui/patui-splash.png)

## Welcome to PaTUI

Homage to [one of the most iconic product launches of this century](https://www.youtube.com/embed/5J-47F8Hrdw?si=zXJN_KIPLTklXwBq) aside, what is PaTUI? 

PaTUI is a terminal-based image editor. Load an image (PNG or JPEG, locally or via URL), and it renders as colored block characters in your terminal. Then paint on it in ~~visual~~ "paint" mode, erase, fill, type text or apply retro filters. When your masterpiece is complete you can export your work as a JPEG, PNG or ANSI art. In all exports, WYSIWYG.

No, we don't dare impose the dogma of higher-fidelities on your artistic vision. What are we, Photoshop? *Please*.

This isn't ~~an Arby's~~ Photoshop. This is *PaTUI*.


## "Zoom, Enhance"

Each pixel in the image is represented by block characters wrapped with ANSI escape codes to render colors.  We're using "True" color with RGB escape codes (e.g. `echo -e "\e[48;2;255;0;255m \e[0m" `) so the vibrance of your original image always shines through.


And, because the original image really is kept around in memory, you can use the "zoom and enhance" feature to zero in on as much or little detail as you need.

![The PaTUI screen with the zoom feature engaged on the loaded image](https://georgemandis.s3-us-west-1.amazonaws.com/patui/patui-zoom.png)





## What pixels want: Vim-based controls

It has Vim-style modal controls (`i` for paint mode, `hjkl` to move, `dd` to delete a "row" of pixels, `yy` to yank, `u` to undo), a 16-color palette you can select with `!@#$%^&*()`, an extended CSS-compatible color palette you can access with `:set color <cornflowerblue|salmon|rebeccapurple,etc>`, and commands like `:w mona-lisa.png` and `:wq`.

Now you can draw shapes and touch up pixels with the most intuitive controls ever invented in computing: arbitrary keys with a generous amount of `Shift` thrown in.

You can always use `:help` for a more exhaustive list.

![The PaTUI help screen shown when you type `:help`](https://georgemandis.s3-us-west-1.amazonaws.com/patui/patui-help-screen.png)



<!--
  TODO: Include a screenshot or terminal recording here.
  A GIF of loading an image and painting on it would be ideal.
  Maybe the Mona Lisa loaded and then someone drawing a mustache on it.
-->

<!--
  Cherry-pick the features that are most delightful/surprising.
  Don't exhaustively list everything -- the README does that.
-->

**Vim motions on pixels.** `5j` moves down 5 rows. `dd` clears a row. `yy` yanks it, `p` pastes. `W` jumps to the next color boundary. `dG` deletes from cursor to bottom. If you know Vim, you already know how to navigate. If you don't know Vim, well, you're going to learn!

**Retro palette filters.** `:palette gameboy` limits your image to the original Game Boy's four shades of green. `:palette cga` gives you the CGA palette. `:dither` applies Floyd-Steinberg error diffusion dithering. Combine them: `:palette gameboy` then `:dither` and suddenly your photo looks like it belongs on a 1989 handheld.

**Find-and-replace for colors.** `:%s/blue/red/g` replaces all blue pixels with red. `:%s/~blue/red/g` does a fuzzy match -- anything in the blue family. The Vim regex muscle memory just... works here.

**Text rasterization.** Press `t` to enter text mode and type characters directly onto the image in the current foreground color. Font size scales with brush size. It's exactly as janky and charming as it sounds.

**Export to ANSI art.** `:w painting.ans` exports your work as ANSI escape codes. `:wc` copies the ANSI art to your clipboard. Paste it into a terminal and it renders in color. Paste it into Slack and confuse your coworkers.

## Wh...Why? Why the terminal? Why any of this?

<!--
  Brief. The terminal as a creative constraint, not a limitation.
  Block characters as pixels. The grid is the canvas.
  There's something satisfying about creative tools that work in
  environments designed for text.
-->

There's something satisfying about creative tools that work in environments designed for text. The terminal gives you a grid of cells, each of which can display a colored block character. That's your canvas. Each cell is a pixel. The constraints are the point.

It's also just funny. The idea of bringing Vim motions to pixel art, of typing `:wq` to save a painting, of having a tool sidebar in a terminal -- it's absurd in a way that makes me happy to work on it.

## How it works

<!--
  Keep this SHORT. People can read the repo.
  Bun + Ink (React for terminals) + sharp for image processing.
  Zustand for state management. The architecture is straightforward.
-->

PaTUI is a [Bun](https://bun.sh) app built with [Ink](https://github.com/vadimdemedes/ink), which is React for terminal UIs. Image loading and manipulation use [sharp](https://sharp.pixelplumbing.com/). State management is [zustand](https://github.com/pmndrs/zustand).

The rendering pipeline: load an image with sharp, downscale it to fit the terminal viewport (accounting for the 2:1 aspect ratio of terminal characters), map each pixel to a 256-color ANSI escape code, and render it as a grid of `▀` (upper half block) characters. Each character encodes two vertical pixels using foreground and background colors.

Edits modify the source image buffer. Undo/redo is a stack of image snapshots. Filters (grayscale, palette limiting, dithering) are applied at render time and included in exports.

## How do you pronounce PaTUI?

It sounds like "patooey," because that's what your images will look like.

## Try It

```bash
# Homebrew (macOS / Linux)
brew install georgemandis/tap/patui

# Or from source
bun install && bun src/index.tsx mona.png
```

Is it practical? Absolutely not. Is it fun? Easily the most fun 5 minutes you'll procrastinate with today.

Built during my time at the [Recurse Center](https://www.recurse.com/) on a lark. View the source and open a PR if you think you can help improve it.

- [github.com/georgemandis/patui](https://github.com/georgemandis/patui)