Heads up. This project was built in an afternoon for RMRRF. Changes from the stock blot were made with the help of AI (Claude Opus). It's not my best work, but it's what I could do with limited time.

A fork of Blot (Hack Club's 2-axis pen plotter) for GRBL-compatibility and photo-to-plotter desktop app. Originally built for RMRRF 2026 as an interactive exhibit. See the original Blot repo for hardware design, assembly instructions, and the stock firmware.
Stock Blot's firmware uses a hand-rolled serial protocol that is inefficient and stuttery. This is okay for the kind of drawings Blot ships with, but it leaves a lot on the table. There's no acceleration planning and no compatibility with existing G-code tools.
firmware/ is a drop-in replacement that teaches Blot to accept reasonably advanced G-code:
- Motion planning. Trapezoidal velocity profiles with junction deviation at corners, planned in Cartesian tip-space so CoreXY diagonals don't get clipped. Buffered streaming at 115200. The host keeps the next 10โ50 moves queued so motion overlaps parsing.
- Native arcs.
G2/G3withI/JorR. No more pre-tessellating circles into a hundred line segments. - Runtime settings.
$110max feedrate,$120max acceleration,$151servo pen-down ยตs, etc. Tuned once with$$and persisted, not baked into firmware. - GRBL-compatible protocol. Any standard G-code sender (Universal G-code Sender, bCNC, OctoPrint+GRBL plugin, or a dumb serial script) can drive it. The pen maps onto GRBL's spindle commands:
M3 S<microseconds>= pen down,M5= pen up.
This is a subset of GRBL 1.1f, not a full reimplementation. Coolant, spindle PWM, probing, tool change, and hard homing are deliberately skipped because a pen plotter doesn't need them. See
firmware/SUPPORTED_COMMANDS.mdfor the exact supported set.
ui/ is a Mac desktop app I made on top of the firmware: it takes a photo (webcam or file), runs it through a stipple / scribble / long-line algorithm, previews the output, and streams the resulting G-code over USB.
I built it for RMRRF 2026 as an interactive exhibit, the UI is just a convenient bundle of photo โ pen strokes โ send for the event. Any GRBL-speaking sender will drive the plotter just fine once the firmware is flashed
Everything else (hardware, wiring, assembly, the Blot bill of materials) is unchanged. Use Hack Club's docs in the original repo for that.
The UI is Mac-only for now as it uses Apple Vision for local background removal and AVFoundation for camera capture. The firmware, however, is cross-platform and can be driven by any G-code sender on any OS.
firmware/ Arduino firmware for the Seeed XIAO RP2040 on Blot
โโโ firmware.ino + *.cpp/*.h โ flash this to the board
โโโ TUNING.md โ calibration after assembly
โโโ SUPPORTED_COMMANDS.md โ full G-code reference
โโโ tools/ โ stream.py, term.py, tune.py
โโโ test/ โ host-side test harness (see test/README.md)
โโโ test_gcode/ โ sample G-code programs for integration tests
ui/ Desktop app (Mac-only for now)
โโโ blot.sh โ launcher
โโโ blot_ui.py โ the Qt app itself
โโโ *_lineart.py โ stipple / scribble / long-line algos
โโโ mask_*.py, remove_bg.swift โ Apple Vision bg-removal helpers
โโโ combing.py โ keeps pen-up travel inside foreground
โโโ blot_vpype.toml, blot.vpy โ vpype profile + CLI recipe
You need macOS 12+, and an assembled Blot plotter.
# 1. Homebrew (skip if you already have it)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 2. Python + pipx
brew install python@3.13 pipx
pipx ensurepath
# close and reopen Terminal so PATH picks up
# 3. vpype + the UI's Python deps
pipx install --python python3.13 "vpype[all]"
pipx inject vpype pyserial scikit-image pyobjc-framework-AVFoundationInstall the Arduino IDE, then:
- Arduino โ Settings โ Additional boards manager URLs, paste
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json. - Tools โ Board โ Boards Manager โ search "pico" โ install Raspberry Pi Pico/RP2040 by Earle F. Philhower.
- Tools โ Board โ Raspberry Pi Pico/RP2040 โ Seeed XIAO RP2040.
- File โ Open โ
firmware/firmware.ino. The IDE picks up the other.cpp/.hfiles in that folder automatically. - Plug in your Blot. Tools โ Port โ pick the
/dev/cu.usbmodemโฆentry. - Click the upload arrow (top-left). Wait for "Done uploading."
After flashing, tools/tune.py walks you through motor calibration. See firmware/TUNING.md.
From the repo root:
chmod +x ui/blot.sh # first run only
./ui/blot.shThe first launch triggers the macOS camera-permission prompt. Click Allow. If you miss it, toggle it back on under System Settings โ Privacy & Security โ Camera.
You'll see a window with three tabs.
Camera: pick your webcam, point it at something, Capture, drag the square overlay to crop, then Use cropped photo โ.
Generate: pick an algorithm (Stipple / Scribble / Long lines), tweak parameters, click Generate. After a few seconds you'll see a plotter preview with each pen layer in its own color. Toggle Branding off if you don't want the HACKCLUB.COM watermark; adjust its Scale slider separately.
Control: plug in the plotter, pick the USB port, Connect. Quick-command buttons handle jog, pen up/down, and setting origin. When ready, click Send G-code to stream the drawing. Pause/Cancel work while it runs.
First, a one-time setup each session (do this after powering up the Blot, restarting it, or changing pens):
- Tape a piece of paper to a flat surface.
- If you're going fast, tape the Blot down too.
- Plug in the Blot. Control tab โ pick the USB port (something like
/dev/cu.usbmodemโฆ) โ Connect. - Home the machine.
- Click Disable motors (M18). The carriage now moves freely by hand.
- Hand-move the carriage to where you want the bottom-left of the drawing.
- Click Enable motors (M17) to lock the carriage in place.
- Click Set origin (G92) to call that spot (0, 0).
- Adjust the pen.
- Click Pen down (M3). The holder drops to its down position.
- Slide the pen into the holder so that when the pen tip is resting on the paper, the holder sits slightly above its mechanical bottom. You want gravity pulling the pen down onto the paper, that way the tip self-levels.
- Tighten the holder around the pen.
- Click Pen up (M5) and verify the tip clears the paper with room to spare.
Then, for every plot (loop this as many times as you want โ as long as the Blot stays powered and doesn't move, origin and pen calibration carry over):
- Capture a photo. Camera tab โ pick your webcam โ Capture โ drag the square overlay to crop โ Use cropped photo โ.
- Generate the drawing. You'll be moved to the Generate tab โ pick an algorithm (Stipple / Scribble / Long lines) โ tweak parameters if you want โ Generate. Wait for the plotter preview to show up; make sure it's what you want before sending it to the plotter.
- Send it. Control tab โ Send G-code. Watch the first few strokes. If anything looks wrong, hit Cancel or press the physical reset on the board.
- When it's done, the pen parks at
X0 Y120so you can lift the paper out without smudging.
Because the protocol is GRBL-compatible, any serial terminal or G-code sender can drive it at 115200 baud. Two helpers ship in firmware/tools/:
term.py: raw serial REPLstream.py: file-based G-code streamer with flow controltune.py: guided motor calibration (uses the$$settings)
Blot itself, and the hardware design, are by Hack Club. This fork just swaps the firmware protocol and bolts a nicer UI on top.