Menu
Projects

Personal toolmacOSMIT

Blockpad

A macOS sketchpad that opens on a hotkey and hands drawings to whatever coding agent you're in. You draw where the boxes go, press copy, and paste. The agent gets the layout as exact structure, not a paragraph and not a screenshot.

The Blockpad window: a floating canvas with a filter panel sketched on it, a collapsible inspector rail, and a tool dock along the bottom

One window, one canvas, one Copy button. It opens over whatever you are already in, and the dock sits along the bottom so the top edge of the drawing stays clear.

GitHub — akaieuan/blockpadM0 shipped · M1 delivery in progress

Free and MIT licensed. Swift 6, SwiftUI, AppKit, macOS 14+, one dependency. Built for myself, open because there is no reason for it not to be.

In simple terms

A sketchpad that opens over your code editor on a keyboard shortcut. You draw where the boxes go, press copy, and paste into a chat with a coding agent.

The problem it solves is narrow and expensive. You are in a repo and you need to say "filters go in a right-hand panel, tabs across the top, reset and apply in the footer." You type it. The agent builds something reasonable and wrong. You correct it. Three rounds later you have spent real tokens, real minutes and real attention reading implementations you are about to throw away. The cost is not the message, it is the rounds.

What gets pasted is the layout as exact structure: coordinates, sizes, colours, nesting. Not a paragraph, and not a screenshot the model has to interpret.

The impact. It removes the correction rounds, which is where the time and the tokens actually go. Free and MIT licensed, written in Swift with a single dependency, because it started as a tool for me.

Why it exists

Figma and Excalidraw are good tools. They are also another tab, another context, a lot of clicks, and an account you have to keep, and the genuinely useful tiers cost money. None of that is wrong for design work. It is all wrong for the ninety seconds where you just need to say where the boxes go.

Because that is usually the whole problem. You are in a repo, working with an agent, and you need to say “filters go in a right-side panel, tabs across the top, reset and apply in the footer.” You type it. The agent builds something reasonable and wrong. You correct it. Closer, still wrong. Three rounds later you have spent real tokens, real minutes, and real attention reading implementations you are about to throw away.

The cost is not the message. It is the rounds.

Blockpad is one hotkey and one canvas. Ctrl+Opt+B, drag four boxes, Cmd+Return, paste. No model inside it, no account, no subscription, nothing agent-initiated, and it never leaves your machine. It is a faster input device for one specific moment, and the constraint is the product.

Loop target: six seconds, with no mouse travel outside the canvas.

Where this came from

I ran design at a startup, and spent most of that stretch building with agentic tools, writing code to produce design rather than the other way round.

What I kept noticing was my own workaround. Any time I needed an agent to actually understand a layout, I would sketch a rough wireframe and screenshot it. Not because the screenshot was good. Because it carried my intent in a way a paragraph never did. It was the fastest way to point at what I meant, so I did it constantly, in whatever tool happened to be open.

The screenshot was always the wrong artifact, though. It hands over a picture of a structure and asks the model to work backwards into the structure again, which it sometimes gets right and sometimes doesn't, and either way you pay for the guess. What was in my head was never pixels. It was “panel on the right, six rows, two buttons in the footer.”

Blockpad is that workaround turned into a tool. Same rough wireframe, same ninety seconds, except it hands over the structure directly instead of a photograph of it.

What actually gets sent

Blocks are typed, so the scene graph serialises to text locally. No inference, no model, no API call. This sketch:

The sketch: a right-hand filter panel with three tabs, six rows each carrying a small checkbox, and Reset and Apply in the footer

becomes exactly this:

Frame 1440x900  @0,0  "Desktop"
  Box 480x900  @960,0  @right-full-height  stroke #55677A  fill #E5E3DF
    Box 136x40  @24,32  @left-top  "All"  fill #DAE5EF
    Box 136x40  @168,32  @top  "Active"
    Box 136x40  @312,32  @top  "Archived"
    Box 424x64  ×6  @24,112  step 0,88  @left
      Box 24x24  @16,20  @left  stroke #6E8B6A
    Box 200x56  @24,800  @left-bottom  "Reset"  stroke #55677A
    Box 200x56  @248,800  @bottom  "Apply"  stroke #B4534A  fill #F6DAD5
  Text  @40,40  @left-top  "main content unchanged"  stroke #55677A
  Text  @40,76  @left  "panel becomes bottom drawer under 768"  stroke #C08A2E

Every block carries an offset from its parent, so the layout reconstructs exactly rather than approximately. Colours are hex, not names: #55677A is a value the receiving agent can paste into CSS, where [slate] would have been a lookup it could not perform. Repeats collapse to a count plus the step between them, so ×6 stays cheap without discarding where the other five are.

On that exact scene:

ModeCostUse
Tree only617 charactersDefault. Structural changes, layout specs.
Image only2,153 tokensWhen proportion or feel matters.
Tree + imagebothAnnotated screenshots, where the tree alone is thin.

The image figure is arithmetic and exact. Anthropic resizes anything over 1568px on the long edge, then charges (width × height) / 750. The sample renders at 3008×1976, which becomes 1568×1030, which is 2,153 tokens.

The tree figure is given in characters, deliberately, because tokens are the thing you cannot estimate honestly. Character heuristics and OpenAI tokenizers both misjudge Claude, and they misjudge it worst on exactly this kind of text: @960,0, #55677A and ×6 tokenize far less kindly than prose. 617 characters is somewhere in the low hundreds of tokens, and pinning it down takes a measurement rather than a ratio. The repo ships a script that runs the tree through Anthropic's count_tokens endpoint and prints the table.

What survives without any measurement is the shape of the gap: a screenshot of this sketch costs over two thousand tokens, and the tree is 617 characters of plain text. That is roughly an order of magnitude, and it holds across any plausible tokenization. It is also structurally more precise: six identical rows collapse to ×6 with an exact count and an exact step, rather than a model counting rectangles in a JPEG and getting five.

An image is not automatically the expensive choice. One 2,000-token picture that lands the layout first time beats four rounds of prose plus four implementations you have to read and reject. The tree is the default because it is cheap and precise, but the mode switcher is right next to the copy button for the times feel matters more than structure.

What decides arguments

  • It persists, it does not dismiss.

    UI iteration is iterative. You send a sketch, the agent builds it, it is 70% right, you nudge two blocks and send again. A launcher that cleared on send would make you redraw every round. So the hotkey toggles rather than summons, contents survive hide, show and restart, the window remembers its size and position, Esc hides without discarding, and clearing is explicit.

  • The tree is the default, not the image.

    The opposite of what every screenshot tool does, and the position the whole project rests on. The mode switcher sits next to the copy button for the times feel matters more than structure.

  • Never press Return.

    Blockpad pastes and stops. The agent might be mid-plan or waiting on a permission gate, and a stray prompt at the wrong moment costs more than the keystroke saves.

  • No model inside it.

    No inference, no account, no cloud, nothing agent-initiated, and nothing leaves the machine. It is an input device.

  • The tree is the only contract.

    Everything the app can draw, including the thirty-two component blockouts, lands in the payload as plain blocks. Nothing gets a private representation the receiving agent would have to be taught.

Using it

It runs as a menu bar item with no dock icon. Two hotkeys toggle the canvas: Ctrl+Opt+B and Ctrl+Opt+Space.

Heads up on Ctrl+Opt+Space. macOS ships that chord bound to “Select next source in Input menu”, and a system binding beats an app's. On a clean machine it does nothing. Either use Ctrl+Opt+B, which nothing else claims, or clear the system one in System Settings, Keyboard, Keyboard Shortcuts, Input Sources.

Tools

1 – 0Tools, left to right along the dock
V H F R O D A L P T ESelect, pan, frame, rect, ellipse, diamond, arrow, line, draw, text, eraser
PadlockKeeps a tool active. Off, it reverts to select after one shape

Shapes and connectors each collapse into one dock slot holding whichever member you used last, with the rest on a flyout.

Canvas

Cmd+ReturnCopy payload
Cmd+Z / Shift+Cmd+ZUndo, redo
Cmd+D · Cmd+ADuplicate, select all
Cmd+[ / Cmd+]Send backward, bring forward. Shift for all the way
Cmd+0 / Cmd+9Zoom to 100%, centre on the drawing
Cmd+BackspaceClear canvas
Double-clickEdit text, or start a text block on empty canvas
Space-drag, scrollPan. Ctrl- or Cmd-scroll or pinch zooms
ViewfinderFits the drawing into the area the chrome is not covering

Alignment guides

Grid snapping gives tidy coordinates but not tidy layouts: two boxes can both sit on the grid and still look a step out. Dragging solves the three interesting lines per axis, both edges and the centre, against every other block, pulls to the nearest match, and draws a guide across the objects that share it. Multi-selection moves as a rigid body, so its internal spacing cannot drift.

Styling

Colour is arbitrary hex, not a fixed palette. Four presets stay inline in each row for the common case. The swatch opens RGB channel sliders with live gradient tracks, a hex field, the colours you reached for recently, the full preset set, and the system picker. Stroke width and corner radius are real numbers you can step, type, or drag to scrub. All of it lands in the tree as values the receiving agent can act on.

The design left the plan three times, on purpose

  • Crisp, not hand-drawn.

    The plan argued that roughness signals provisional and stops a model reading proportions as exact. That risk turned out to be covered elsewhere: the tree states coordinates and counts outright, so precision never depends on the picture. The default is clean geometry and the sketch renderer survives behind a toggle.

  • A dock, not a top bar.

    The top edge of a drawing is where you look, so tools moved to the bottom. The inspector became a collapsible rail of rows: leading glyph, quiet label, control on the trailing edge, hairline between.

  • Arbitrary colour.

    The plan said five swatches and no picker, and listed a colour picker as a non-goal. Both reversed, and the payload got better for it: hex is a value the receiving agent can paste into CSS, where a palette name was a lookup it could not perform.

The mark is the operation

128px64px32px18px

A card on Apple's icon geometry, 22.37% corner radius, holding an isometric stack of three faces with three short rules radiating from where they meet. It is a blockout of a layout seen in three dimensions, which is close to literally what the app does. The top face is the only colour in it.

There are two masters, dark and light, and they are not inversions of each other: the card runs near-black or near-white with a soft vertical gradient, the two side faces carry their own greys per theme, and only the orange stays put. On this page the palette swaps in CSS, so the drawing stays one server-rendered SVG rather than a component that has to read the theme.

It is generated in Core Graphics from the palette rather than stored as a binary asset, so changing a swatch changes the icon, and ./Scripts/icon.sh regenerates it from code. The SVG is emitted from the same ratios, so vector and raster cannot drift.

Why native, not a web app

A web app cannot register a global hotkey, cannot read which application was frontmost, and cannot post a synthetic paste event, which is the entire delivery mechanism rather than a detail of it. Tauri could do all three, but would spend a webview against a six-second loop.

The canvas is an NSView drawing through Core Graphics, hosted in SwiftUI. AppKit because hit testing, drag handles and marquee select get miserable in pure SwiftUI past forty blocks, and UndoManager comes free.

Tech stack

Swift 6 · SwiftUI · AppKit · Core Graphics · macOS 14+

One dependency, KeyboardShortcuts, and nothing else yet. No backend, no account, no inference, nothing leaves the machine.

Not App Store: the sandbox blocks synthetic events and cross-app activation, so it ships as a signed, notarised DMG.

State of play

M0 is done, and the app has moved a long way past it.

Shipped

  • Menu bar item, no dock icon, two hotkey toggles, persistent resizable canvas
  • Frame, rectangle, ellipse, diamond, arrow, line, freehand, text, eraser, pan
  • Arbitrary hex on stroke and fill, numeric stroke width and corner radius, fill patterns, opacity, layer order
  • Alignment guides, grid snap, marquee select, rigid-body multi-selection, undo/redo
  • A component drawer of thirty-two blockouts across Layout, Controls, Data and Feedback
  • Tree serialiser with run-collapsing, three payload modes, clipboard copy
  • Crisp renderer by default, the sketch renderer one toggle away
  • App icon generated in Core Graphics from the palette, MIT licensed

Next

M1, delivery. Today Blockpad copies and you paste. M1 captures the frontmost app before the panel takes focus and pastes into it directly: text everywhere, images into editors, and a written-to-disk path for terminals, which is what makes CLI agents work at all. The pure-logic half is built and tested; the paste itself is not yet wired. Riskiest milestone, and the one the whole idea rests on.

Non-goals

Not a design tool. No layers panel, no Figma export, no collaboration, no cloud, no account, no LLM inside the app, and no Windows until the Mac version is actually good.

The colour picker used to be on this list. It is not any more.

Who built it

Ieuan King, design and build, out of Ubik Studio. MIT licensed, so anyone can fork it, ship it, or take the tree format and do something better with it.

Why this one matters to me

Design tools assume you are doing design. Most of the time I am not. I am trying to be understood by something that will write the code, and the gap between what I can see in my head and what I can type is where the time goes.

This does not make anything prettier. It makes intent cheap to transmit, so anyone who can drag a rectangle can specify an interface well enough to have it built. For internal tools, the ones nobody staffs a designer on, that is most of the value.