kwonsean/claude-code-paint
paint
A paint canvas that lives in a Claude Code pane, opened with /paint and drawn with the mouse; supports palette colors, brush sizes, flood fill, straight lines, mirror mode, custom colors, undo/redo, resizable canvas, SVG save, and copy as JS code or ASCII art.
关于这个 mod
An early (0.9) Claude Code plugin that renders a pixel paint canvas inside a pane. Open it with /paint and drag with the mouse: left button draws, right button erases. It offers a nine-color palette plus eraser, brush sizes 1-4, flood fill, straight lines (with Shift snapping), mirror modes (left-right, up-down, both), custom colors via a 64-color picker or #rrggbb input, 20-step undo/redo, a resizable canvas (24-160 x 12-100 px), and English/Korean UI. Drawings can be saved as SVG to ~/Pictures, copied as a JS/TS SPRITE array or as ASCII art, or printed in chat with /paint export. The canvas is drawn with half blocks (two pixels per character) via a Client module (hooks/canvas.ts) for smooth dragging, while the hooks module (hooks/register.ts) handles host actions like saving, clipboard, resizing and language. It makes no network requests and writes files only on save or when the clipboard is unavailable. Install with: /plugin install paint --marketplace kwonsean/claude-code-paint. Note: do not press Ctrl+Z in the pane, as Claude Code uses it to suspend itself; use z and x for undo/redo.
安装
请先查看作者 README 确认 marketplace 和插件名称;命令可能随仓库结构改变。
claude plugin marketplace add kwonsean/claude-code-paint claude plugin install paint@claude-code-paint
原文 / README
paint
A paint canvas that lives in a Claude Code pane. Open it with /paint and draw with the mouse.
- Drag to draw (left button), drag with the right button to erase
- Palette of 9 colors plus an eraser, brush sizes 1-4, flood fill, straight lines
- Mirror mode: draw one half and the other half follows (left-right, up-down, or both)
- Custom colors: change any of the nine palette colors, by clicking in a picker of 64 colors or by typing any
#rrggbb(a field under the canvas, or/paint color 3 #ff8800) - Undo / redo (20 steps), resizable canvas, English and Korean
- Save as SVG, or copy the drawing as a JS/TS array or as ASCII art
- A help block with all the shortcuts sits under the canvas (fold it with
?); the status line shows the tool, brush, color, undo depth and mirror mode
Status: early (0.9). It was built against Claude Code's mod API and tested with a simulated engine and the API's type definitions. How mouse drags and
Shiftreach it depends on your terminal (see Terminals). Issues and reports of what works where are welcome.
Install
/plugin install paint --marketplace kwonsean/claude-code-paint
(Claude Code 2.1.275 or later. Or from a shell: claude plugin marketplace add kwonsean/claude-code-paint, then claude plugin install paint@claude-code-paint.) Restart Claude Code, then run /paint.
Use
/paint opens the pane. Click the canvas once so the keys reach it.
| | |
|---|---|
| Draw / erase | drag with the left / right mouse button |
| Colors | 1-9, 0 is the eraser (or click the swatches). Change a color: k opens the color picker, see Custom colors |
| Reset colors | r puts the chosen swatch back to its default, Shift+R all of them (or the reset chips in the picker) |
| Tools | p pen, l line, f fill, b brush size (1-4) |
| Mirror | m cycles off → left-right → up-down → both → off, or click the chips on the fourth menu row |
| Straight line | the Line tool (l), or hold Shift while dragging (snaps to 0 / 45 / 90°) |
| Undo / redo | z / x (or Shift+Z). Not Ctrl+Z: see the warning below |
| Clear | c (undoable) |
| Save | e writes ~/Pictures/paint-<time>.svg |
| Copy as code | j copies the drawing, cropped, as const SPRITE = ["..R..", ...] plus a PALETTE |
| Copy as ASCII | a copies it as █▓▒░ blocks, two characters per pixel, brighter colors denser |
| Help | ? or h folds / opens the help block |
| Language | the chip at the end of the third row, or /paint en / /paint ko (Korean is the default) |
⚠️ Do not press
Ctrl+Zin the pane. On macOS and Linux Claude Code uses it to suspend itself (Claude Code has been suspended. Run fg to bring Claude Code back). The key never reaches the canvas and your session stops until you typefgin the shell. Usezfor undo andxfor redo, or the chips. The canvas also acceptsCtrl+_(Claude Code's own undo key for its input box) andCtrl+Ywhere the terminal passes them on.
The last JS/ASCII export can be printed in the chat with /paint export. If the terminal has no clipboard path, exports are written to ~/Pictures instead.
Custom colors
Each of the nine palette colors can be set to any color you like.
Pick from a palette. Choose a swatch (click it, or press its number), then open the color picker with the ◐ Edit color chip on the fourth menu row, with k, or by clicking the chosen swatch once more. A block of 64 colors opens under the canvas: sixteen hues in a light, a medium and a dark shade, then sixteen grays from white to black, and a row of reset chips below them. Click one and it becomes the chosen swatch's color. The picker's first line says which swatch you are changing and what color it has now, and a dot marks that color if it is one of the 64. The eraser (0) cannot change, so the picker asks you to choose a swatch from 1-9 first. Close it with the same chip or k.
Taking colors back. The last row of the picker shows the default of the chosen swatch (Default for color 3: #facc15) and two chips, ↺ Reset this color and ↺ Reset all. A chip is drawn dim when it would change nothing (the swatch is already its default, or no color has been changed), and clicking a dim chip does nothing. The keys work without opening the picker: r resets the chosen swatch and Shift+R resets every swatch. Because the picture stores swatch numbers, resetting a color also turns the pixels drawn with it back to the default color. Changing or resetting colors is not part of undo.
Or type a color. Enter it in the Color field under the canvas, or use the command:
| Enter | Meaning |
|---|---|
| #ff8800 | the selected swatch becomes this color |
| 3 #ff8800 or 3=#ff8800 | swatch 3 becomes this color |
| #f80, ff8800, rgb(255,136,0) | other ways to write a color (the # is optional, three-digit hex is expanded) |
| reset / reset all | every color back to the defaults |
| reset 3 | only swatch 3 back to its default (the same as the chips and keys above) |
| /paint color | lists the nine colors (/paint color 3 #ff8800 changes one, /paint palette … and /paint colors … also work) |
Things to know:
- The picture stores which swatch each pixel uses, so changing a swatch recolors every pixel already drawn with it (like an indexed palette).
- The eraser (
0) has no color and cannot be changed. A bare#ff8800with the eraser selected is refused; give a number instead (3 #ff8800). - The picker and the field work on the same colors: a color you picked can be changed again by typing, and the other way round.
- The swatch labels switch between black and white text, whichever reads better on the color. The status line shows the selected color's code (
Color 3 #facc15). - The SVG, the JS code (
PALETTE) and the ASCII brightness all use your colors. In the JS export's comment a changed color is named by its hex code instead of its name (B #2dd4bf), and the letters (R O Y G B P M W K) stay tied to the swatch numbers. - Custom colors last for the session: they are not saved to a file, so a new Claude Code session starts with the defaults.
Mirror mode
Turn it on with m (or click a chip on the Mirror row) and everything you do is repeated across the middle of the canvas:
| Mode | What is repeated | |---|---| | Left-right | each pixel also appears on the other side of the vertical center line | | Up-down | the same across the horizontal center line | | Both | all four corners: a pixel and its three images |
It covers drags with the pen, the Line tool (including Shift lines and the live preview), erasing with the right button, flood fill (it fills the mirror image's region too) and every brush size (an even brush mirrors pixel for pixel). While it is on, the empty pixels on the axis are drawn a little lighter so you can see where the middle is, and the status line says which mode is active. One undo removes a whole mirrored stroke. Mirror mode is a setting, not a drawing step: it is not part of undo, and resizing the canvas keeps it.
Canvas size
Change it with the − + chips (or [ ]), /paint bigger|smaller, /paint 100x60, or by typing it in the field under the canvas. Separate the numbers with x, *, × or a space: 100x60, 100*60, 100 60.
| | width | height | |---|---|---| | minimum | 24 px | 12 px | | maximum | 160 px | 100 px |
The height is made even (two pixels share one character row, so 25 becomes 24). A value outside the limits is moved to the nearest limit and you are told what it became. The menu rows keep their full width even on a narrow canvas. Resizing keeps what fits of the drawing (from the top left) and clears undo/redo.
A new canvas is 32 × 32 px. + and − change the width and the height together, 8 px each, so a square canvas stays square. When one side reaches its limit, only the other side keeps changing:
- Growing: the width stops at 160 px or at the columns your pane has, whichever is smaller, and the height at 100 px. In a narrow pane (say 70 columns) the canvas grows square up to the pane's width and then only taller; in a wide pane the height limit comes first (96 × 96 → 104 × 100) and then only the width grows, up to 160.
- Shrinking: 32 × 32 → 24 × 24, then only the height goes down to 12 (24 × 16 → 24 × 12).
How it works
The canvas is drawn in pixels, two to a character with a half block (▀: the top pixel is the character color, the bottom pixel the background). Mouse and keys are handled on the surface by a Client module (hooks/canvas.ts), so dragging stays smooth; the hooks module (hooks/register.ts) opens the pane and does what needs the host: saving files, the clipboard, resizing the pane, the size field and the language.
What it touches
From the mod API's own report of what the code calls: it reads the HOME environment variable, writes files only when you save or when an export cannot use the clipboard (into ~/Pictures), and uses the clipboard when you ask it to copy. It makes no network requests and runs no other programs.
Terminals
- Mouse drags need a terminal that passes mouse events to the program. Sub-cell precision (smoother vertical position) comes from terminals that report pixels: kitty, Ghostty, iTerm2, WezTerm. Elsewhere the top pixel of a character cell is used.
- Many terminals keep
Shift+drag for selecting text and never pass it on. Use theLinetool there. Ctrl+Zis taken by Claude Code (it suspends the session, see the warning under Use). On a Mac the terminal also keepsCmd+Zfor its own Edit menu, and the key event the mod receives has no flag for the Cmd key, soCmd+Zcannot be used either.zandxalways work.
Keys do nothing?
- Click the canvas once first: the keys only reach the canvas after a click gives it the focus (
Eschands the focus back). - Restart Claude Code after an update: a running session keeps the old version.
- Run
/paint debug, click the canvas and press the key. The status line then shows the last key and mouse event that actually arrived, for exampledebug · key 3: {"key":"z","ctrl":true} · pointer 2: up left 9,8. If a key you pressed never changes thekeycount, the terminal or Claude Code is keeping it and the canvas never sees it; use another key (z/x) or the chips. Run/paint debugagain to turn it off.
Development
hooks/register.tsis the hooks module,hooks/canvas.tsthe surface module (it is self-contained, so its palette and limits are copies of the ones inregister.ts; keep them in step).tests/uses the engine's testing helpers (claude-code/testing).- Check a change with
claude plugin validate .. After editing an installed copy, bumpversionin.claude-plugin/plugin.jsonand runclaude plugin update paint@claude-code-paint, because installed plugins run from a cached copy.
License
한국어
⚠️ 패널에서
Ctrl+Z를 누르지 마세요. macOS와 Linux에서는 Claude Code가 이 키를 자기 일시 정지(suspend)에 써서(Claude Code has been suspended. Run fg to bring Claude Code back) 캔버스에 도착하지도 않고 세션이 멈춰요. 터미널에fg를 입력하면 돌아와요. 되돌리기는z, 다시 실행은x(또는 화면의 칩)를 쓰세요. Mac의Cmd+Z도 터미널이 자기 메뉴에 쓰기 때문에 못 써요.
키가 안 먹을 때: 캔버스를 한 번 클릭한 뒤 누르세요. 업데이트한 뒤에는 Claude Code를 재시작해야 해요.
/paint debug를 켜고 캔버스를 클릭한 뒤 키를 누르면 상태 줄에 실제로 도착한 키와 마우스 입력이 나와요 (key숫자가 안 늘면 터미널이나 Claude Code가 그 키를 가져가는 거예요). 다시/paint debug로 끄세요.
패널을 그림판처럼 씁니다. /paint 로 열고 마우스를 끌어서 그립니다.
-
왼쪽 버튼으로 그리고, 오른쪽 버튼으로 지웁니다. 위쪽 줄에서 색(0은 지우개)과 도구를 클릭하거나, 캔버스를 한 번 클릭한 뒤 키로 고릅니다.
-
키:
1-9색,0지우개,p펜,l직선,f채우기,m대칭,b굵기(1-4),z되돌리기,x다시 실행(Shift+Z도 돼요),c지우기,e저장 -
직선:
직선도구(l)는 누른 곳에서 끌고 있는 곳까지 곧은 선을 그려요. 펜이나 직선 도구에서Shift를 누른 채 끌면 가로·세로·45° 중 가까운 쪽으로 맞춰져요. (터미널에 따라 Shift+드래그는 텍스트 선택에 쓰여서 프로그램에 안 넘어올 수 있어요. 그럴 땐직선도구를 쓰세요.) -
대칭(미러) 모드:
m키나 네 번째 메뉴 줄의 칩으로 켜면, 칠하는 모든 것이 캔버스 가운데를 기준으로 반대쪽에도 똑같이 찍혀요.- 모드는
좌우,상하,4방향이에요.m을 누를 때마다 좌우 → 상하 → 4방향 → 끔 순서로 바뀌어요. - 펜, 직선 도구(Shift 직선과 미리보기 포함), 오른쪽 버튼 지우개, 채우기(반대쪽 영역도 함께 채워요), 모든 굵기가 대칭으로 동작해요.
- 켜 있는 동안 가운데 줄(축)의 빈 픽셀이 조금 밝게 보이고, 상태 줄에
대칭 좌우같은 표시가 나와요. 한 번 되돌리기로 대칭 획 전체가 사라져요. 대칭 설정은 되돌리기 대상이 아니에요.
- 모드는
-
색 지정: 팔레트 9색을 원하는 색으로 바꿀 수 있어요.
- 팔레트에서 고르기: 색 견본을 고른 뒤(클릭하거나 숫자 키) 네 번째 메뉴 줄의
◐ 색 편집칩,k키, 또는 이미 고른 견본을 한 번 더 클릭하면 캔버스 아래에 64색 선택 팔레트가 열려요. 16가지 색상의 밝은색·보통·진한색 세 줄과 흰색에서 검정까지 회색 한 줄이에요. 누르면 바로 그 견본의 색이 돼요. 맨 윗줄에 어느 견본을 바꾸는 중인지와 현재 색이 나오고, 현재 색이 64색 중 하나면 ● 표시가 붙어요. 지우개(0)는 바꿀 수 없어서 1-9번을 먼저 고르라고 안내해요. - 기본값으로 되돌리기: 선택 팔레트의 맨 아랫줄에 고른 견본의 기본색(
색 3 기본값: #facc15)과↺ 이 색 초기화,↺ 모두 초기화칩이 있어요. 바꿀 게 없으면(이미 기본색이거나 바꾼 색이 하나도 없으면) 칩이 흐리게 보이고 눌러도 아무 일도 안 일어나요. 팔레트를 열지 않아도r은 고른 견본을,Shift+R은 모든 견본을 기본값으로 되돌려요. 그림은 견본 번호를 기억하기 때문에, 초기화하면 그 색으로 그린 픽셀도 기본색으로 돌아가요. 색 변경과 초기화는 되돌리기 대상이 아니에요. - 직접 입력하기: 캔버스 아래 색 입력칸에 입력하거나
/paint color 3 #ff8800명령을 쓰세요. #ff8800은 고른 색,3 #ff8800은 3번 색을 바꿔요.#f80,ff8800,rgb(255,136,0)도 돼요.reset은 모든 색을,reset 3은 3번 색만 기본값으로 되돌려요./paint color는 현재 색 목록을 보여 줘요.- 그림은 "어떤 번호의 색인지"를 기억해서, 색을 바꾸면 이미 그린 픽셀도 새 색으로 바뀌어요. 지우개(0)는 바꿀 수 없어요.
- SVG 저장, JS 코드, ASCII 내보내기에 모두 바꾼 색이 쓰여요. 바꾼 색은 이번 세션 동안만 유지돼요.
- 팔레트에서 고르기: 색 견본을 고른 뒤(클릭하거나 숫자 키) 네 번째 메뉴 줄의
-
캔버스 아래에 도움말(단축키 목록)이 있어요.
?(또는h) 키나 첫 줄 끝의?칩으로 접고 펼쳐요. -
저장하면
~/Pictures/paint-날짜.svg가 만들어집니다. -
크기:
−+칩,[]키,/paint 100x60, 또는 캔버스 아래 입력칸에 직접 입력해요. 구분은x,*,×, 공백 모두 돼요 (100x60,100*60,100 60).| | 가로 | 세로 | |---|---|---| | 최소 | 24 픽셀 | 12 픽셀 | | 최대 | 160 픽셀 | 100 픽셀 |
세로는 짝수로 맞춰져요 (픽셀 둘이 글자 한 줄을 나눠 써서요: 25 → 24). 범위를 벗어나면 가장 가까운 한계로 맞추고 무엇으로 바꿨는지 알려 줘요. 캔버스가 좁아도 메뉴는 잘리지 않아요.
처음 캔버스는 32 × 32 픽셀이에요.
+−는 가로와 세로를 같이 8픽셀씩 바꿔서, 정사각형이면 계속 정사각형이에요. 한쪽이 한계에 닿으면 나머지 한쪽만 계속 바뀌어요.- 키울 때: 가로는 160픽셀과 패널의 가로 칸 수 중 작은 쪽까지, 세로는 100픽셀까지예요. 터미널이 좁으면(예: 70칸) 가로가 패널 너비에 닿을 때까지 정사각형으로 커지고 그다음엔 세로만 늘어요. 넓으면 세로 한계가 먼저 와서(96×96 → 104×100) 그다음엔 가로만 160까지 늘어요.
- 줄일 때: 32×32 → 24×24, 그다음엔 세로만 12까지 줄어요 (24×16 → 24×12).
-
언어: 세 번째 줄 끝의 칩이나
/paint en/paint ko로 영어와 한국어를 바꿔요. -
한 글자에 세로 픽셀 둘을 넣는 반블록으로 그려서, 터미널이 마우스 위치를 픽셀 단위로 알려 주면(kitty, Ghostty, iTerm2, WezTerm) 더 정확하게 그려집니다.
내보내기: JS 코드 복사(j) 는 그린 부분만 잘라 const SPRITE = ["..R..", ...] 배열과 PALETTE 로, ASCII 복사(a) 는 밝기에 따라 █▓▒░ 블록 글자로 클립보드에 넣어요. /paint export 는 마지막으로 내보낸 내용을 채팅에 띄웁니다. 클립보드를 못 쓰면 ~/Pictures 에 파일로 저장해요.

