Turn your phone into a pressure-sensitive drawing tablet for your Mac, over Wi-Fi.
PenBridge pairs your Android phone with your Mac. A small menu-bar app on the Mac receives pen input (pressure, tilt, hover and the side button) and turns it into native tablet events, so your drawing app sees a real pen rather than a mouse. Two to four fingers work like a Mac trackpad: scroll, zoom, swipe and Mission Control. The main target device is a Samsung Galaxy S23 Ultra with its S Pen, but any phone works with a finger.
πΈ Screenshots coming soon.
flowchart LR
subgraph Phone["π± Phone (Android)"]
direction TB
Pen["S Pen / finger"] --> Sampler["Sampler<br/>pressure Β· tilt Β· hover Β· buttons"]
Sampler --> Filter["Pen-first filter<br/>palm rejection"]
end
subgraph LAN["πΆ Local network"]
direction TB
Bonjour["Bonjour discovery<br/>_penbridge._tcp"]
TLS["TLS control channel<br/>J-PAKE pairing (PIN / QR)"]
UDP["Encrypted UDP pen stream<br/>AES-256-GCM"]
end
subgraph Mac["π» Mac menu-bar server"]
direction TB
Tracker["Pen state tracker"] --> Gestures["Trackpad gestures<br/>scroll Β· pinch Β· swipe"]
Gestures --> Mapping["Display mapping"]
Mapping --> Inject["CGEvent tablet events"]
end
App["π¨ Your drawing app"]
Filter --> UDP --> Tracker
Mac -. advertises .-> Bonjour -. found by .-> Phone
Phone <-. pairing + session key .-> TLS <-.-> Mac
Inject --> App
- Discover. The Mac advertises itself over Bonjour. The phone finds it, or you enter host and port by hand on networks without mDNS.
- Pair once. The Mac shows a 6-digit PIN and a QR code. The phone proves it knows the secret with J-PAKE, and both sides store a device key.
- Draw. Each stroke streams as small encrypted UDP datagrams. Every packet carries the full pen state, so a lost packet is corrected by the next one.
- Inject. The Mac turns the stream into tablet proximity, down, drag and up events with pressure and tilt, mapped onto the display you choose.
Pairing and connecting, step by step
sequenceDiagram
autonumber
participant P as π± Phone
participant M as π» Mac
M-->>P: Bonjour advert (version, name, cert fingerprint)
P->>M: TLS connect + hello / version check
Note over M: Shows PIN + QR
P->>M: J-PAKE with PIN or QR token
M->>P: J-PAKE, confirmation bound to the Mac's cert
Note over P,M: Both store device key, phone pins the cert
P->>M: Later: reconnect, authenticated with the device key
M->>P: Per-session input key
P-)M: Encrypted UDP pen samples
Everything marked β works end to end, checked on a Galaxy S23 Ultra with a Mac. β³ is planned.
Drawing
- β βοΈ Pressure and tilt from the S Pen, sent as native macOS tablet events
- β π«§ Hover: the cursor follows the pen before it touches the screen
- β π S Pen side button: right-click while hovering, a right-button drag while the tip touches
- β ποΈ Palm rejection: pen first, so fingers and palms are ignored while the pen is near
- β π Finger cursor mode: one finger moves the cursor like a trackpad, relative to where it is (ADR-0026): tap to click, double-tap to double-click, tap-and-a-half to drag. Switch it to Draw to paint with a finger instead
- β β‘ Low latency over UDP, keeping the S Pen's historical samples: about 3 ms median and 8 ms p95 from the phone sending a sample to the Mac injecting it, over Wi-Fi (numbers)
Gestures, like a Mac trackpad (ADR-0023, table)
- β βοΈ Two fingers: scroll with momentum, swipe between pages, pinch to zoom and rotate, tap to right-click, double-tap for smart zoom (following the macOS Smart Zoom setting; with it off, right-click is instant)
- β π€ Three-finger drag: move windows and select text
- β ποΈ Four fingers: Mission Control, App ExposΓ©, switch Spaces, show desktop and the Apps launcher
- β π― Acts at the cursor, which stays put; scroll direction follows the macOS natural-scrolling setting
- β βοΈ The pen always wins: bringing the pen near cancels a gesture and its momentum
Phone app
- β π Finds your Mac by itself on the local network, and connects to the last Mac you used
- β π· Pair with a QR code or a PIN; forget a Mac and re-pair it from Settings
- β π Reconnects after Wi-Fi drops or when you come back to the app
- β π«οΈ Faint ink echo: a short trail that fades, so you can see where the pen went
- β π’ Status dot for the connection; tap it for latency, orientation, Disconnect and Change Mac
- β π Orientation toggle: landscape (default), portrait or auto
- β βοΈ Settings for finger mode, finger pressure, finger hold before drawing and palm size
- β πΌοΈ App icon: an adaptive launcher icon that also works as a themed icon
- β π No telemetry: the app talks to your Mac and nothing else (ADR-0020)
Mac app
- β π§ Menu-bar app with no Dock icon: run at startup, a pause hotkey (ββ₯βP), live connection stats, a display picker and Open logs
- β π Secure pairing with a PIN or QR code (J-PAKE) in a floating window on the Mac, and encryption on every channel
- β πͺΆ Light on the Mac: a NativeAOT build with about a 20 MB footprint, a 168 ms launch and 0% CPU when idle
- β π² Multiple paired phones; one draws at a time
- β πΌοΈ App icon in Finder, the DMG and Login Items, with matching menu-bar glyphs for each state
Settings, on the Mac (Settingsβ¦, β,) and from the phone (table)
- β πΊοΈ Display and region mapping: the main display, a chosen one or All displays as one desktop, or a region you drag on a display, optionally locked to the phone's aspect. The phone outlines the area that maps onto the Mac and dims the rest, so strokes are never squashed (ADR-0031)
- β π±οΈ Pen or Mouse: absolute like a tablet, or relative like a mouse with its own speed and acceleration
- β π Side button actions: right click, middle click, eraser while held, double click or nothing
- β π Pressure curve: tip feel from soft to firm, click threshold and full-pressure point, with a live test pad on the Mac (ADR-0032)
- β βοΈ Gesture settings: pointer and scroll speed, Smart Zoom (follow macOS, on or off), and switches for pinch, rotate, three-finger drag and four-finger gestures (ADR-0033)
- β πͺ Window or region from the menu bar (1.3.0): Display βΈ Full display / Windowβ¦ / Regionβ¦. Windowβ¦ maps the pad to a window you click, and the mapping follows it as it moves or resizes. Regionβ¦ opens an editor like the macOS screenshot tool: move, resize by 8 handles, Done or Cancel (ADR-0035, ADR-0036)
- β π Tint outside the active area (1.3.0): while the phone is connected, the Mac dims everything outside the region or window. It never catches clicks and can be turned off on the Mac or the phone
- β ποΈ Precise sliders: type a value, step it with the arrows or β/+, and a drag snaps at the default (1.2.1)
- β π Edit the Mac from the phone: every Mac setting except drawing the region, synced both ways and applied at once (ADR-0030)
- β π¨ Phone surface look: corner ticks and dimmed margins around the mapped area, an optional centre marker, background and marker opacity
Beta, 1.3.0. 1.3.0 adds a window target that follows the window, a macOS-style region editor, and a tint outside the active area, all from the menu bar's Display submenu (#213, #241, #243). It was checked on the S23 Ultra against the release build of the Mac app. The new tint switch needs a 1.3.0 Mac; older phones simply don't show it. 1.2.1 added typed values, steppers and a snap at the default to every settings slider on the Mac and the phone, and makes a two-finger twist rotate reliably instead of zooming (#212, #214). Phase 5 (1.2.0) is done, and with it the MVP: mapping, pen and gesture settings live in a Settings window on the Mac and can be edited from the phone, and the phone shows the part of its surface that maps onto the Mac. Phase 5 was checked on the S23 Ultra against the release build of the Mac app (#160). The wire protocol is now 1.2; 1.0 and 1.1 phones and Macs still work with 1.2 ones: the phone then has no Mac section and keeps its whole surface active, and the Mac's pen settings still apply. Known issue: on a Mac without a trackpad, a second smart-zoom double tap in Preview zooms into the next block instead of back out, a quirk of Preview with always-visible scroll bars. Set System Settings β Appearance β Show scroll bars to When scrolling to avoid it (#144). Phase 4 (1.1.0) added trackpad-parity gestures (#110), and Phase 3 (1.0.0), the first release, was verified on the S23 Ultra (#66).
| Phase | Scope | Status | Release |
|---|---|---|---|
| 0 | Repo bootstrap: conventions, CI/CD skeleton, toolchain | β Done | |
| 1 β Core (#10) | Protocol, security, input processing, network engine and SimClient | β Done | |
| 2 β Mac server (#11) | Menu bar, run at startup, pause hotkey, Bonjour, PIN/QR pairing window, Accessibility, CGEvent injector, NativeAOT | β Done | |
| 3 β Android client (#12) | Drawing surface, S Pen, palm rejection, finger cursor mode, discovery, QR/PIN pairing, reconnect, on-device checks on the S23 Ultra | β Done | 1.0.0 |
| 4 β Gestures (#13) | Trackpad-parity gestures: two-finger scroll, momentum, swipe pages, pinch/rotate, tap, smart zoom; three-finger drag; four-finger system gestures. App icon | β Done | 1.1.0 |
| 5 β Settings (#14) | Settings window on the Mac, edited from the phone too: display/region mapping, Pen/Mouse mode, side button, pressure curve, gesture settings, phone surface look | β Done | 1.2.0 |
| Windows host (#28) | Tray server for Windows: pen injection, gestures, pairing, settings | β³ Later | |
| Publishing (#177) | Google Play, signed and notarized Mac app | β³ Later | |
| Screen mirroring (#16) | The Mac or Windows screen shown under the pen on the phone | β³ Later | |
| iOS client (#18) | iPad/iPhone client with Apple Pencil | β³ Later | |
| S Pen Air Actions (#19) | S Pen remote button and air gestures as configurable shortcuts | β³ Later | |
| Mac gestures (#193) | Interactive four-finger gestures | β³ Later |
The MVP is phases 1β5. Every phase ends with a release on GitHub Releases (ADR-0021): Phase 3 is 1.0.0, the first release, and each later phase bumps the minor version. Bug-fix releases between phases bump the patch (1.1.1 β¦). After the MVP, each milestone above ships as its own minor release, in no fixed order (ADR-0034). All work is tracked in issues and milestones.
| Minimum | |
|---|---|
| π» Mac | macOS 14 (Sonoma) or later, Apple Silicon or Intel |
| π± Phone | Android 10 (API 29) or later |
| ποΈ Stylus | Optional. Built and tested for the Galaxy S23 Ultra's S Pen; without one, a finger works |
| πΆ Network | Phone and Mac on the same local network |
Download both apps from the latest release:
| File | For |
|---|---|
PenBridge-X.Y.Z-macos.dmg (or .zip) |
the Mac menu-bar app |
PenBridge-X.Y.Z-android.apk |
the phone |
SHA256SUMS |
checking the downloads: shasum -a 256 -c SHA256SUMS --ignore-missing |
The app is ad-hoc signed and not notarized yet (#21), so Gatekeeper warns on first launch:
- Open the
.dmgand drag PenBridge to Applications. - In Finder, right-click PenBridge β Open β Open. On macOS 15+, if there's no Open button, launch it once, then click Open Anyway in System Settings β Privacy & Security.
Or, in Terminal:
xattr -dr com.apple.quarantine /Applications/PenBridge.app - Grant Accessibility when PenBridge asks. It needs this to post pen events. After an update you may have to remove PenBridge from the Accessibility list and add it again.
PenBridge lives in the menu bar; there's no Dock icon.
The APK isn't on Google Play, so sideload it:
- Download the
.apkon the phone and open it. - Allow installs from your browser or Files app when Android asks, then tap Install. If Play Protect warns, choose More details β Install anyway.
Or, from a computer:
adb install -r PenBridge-X.Y.Z-android.apk
- Put the phone and the Mac on the same network.
- On the Mac, choose Pair new device⦠from the PenBridge menu. A window shows a QR code and a 6-digit PIN.
- Open PenBridge on the phone. Your Mac shows up in the list: pick it and scan the QR code, or type the PIN.
- Draw. Next time, the phone connects to that Mac by itself.
Open a pressure-aware app such as Krita to see pressure and tilt. More details are in docs/releasing.md and macOS signing.
With the pen away from the screen, use fingers like a trackpad. Gestures act where the cursor is.
| Fingers | Motion | Action |
|---|---|---|
| 2 | Move | Scroll, with momentum after a flick |
| 2 | Swipe left or right | Back and forward between pages (Safari and other apps that support it) |
| 2 | Pinch or twist | Zoom and rotate |
| 2 | Tap | Right-click |
| 2 | Double-tap | Smart zoom (if on in System Settings β Trackpad) |
| 3 | Move | Drag (move a window, select text) |
| 4 | Swipe up / down | Mission Control / App ExposΓ© |
| 4 | Swipe left / right | Switch Space or full-screen app |
| 4 | Spread / pinch | Show desktop / Apps launcher |
- Zoom, rotate and smart zoom reach only the frontmost app, as on a trackpad.
- A twist rotates and a pinch zooms: whichever clearly dominates starts first, and the other joins only after a further 15Β° or 25 %. Apps such as Preview follow only the first.
- Four-finger gestures fire once per gesture through the default Mission Control keyboard shortcuts (ββ ββ ββ ββ, and F11 for show desktop), so those need to be on in System Settings β Keyboard β Keyboard Shortcuts β Mission Control.
On the Mac, choose Settingsβ¦ from the PenBridge menu (β,). On the phone, open Settings: while connected, it has a section for the Mac's settings, and changes apply on the Mac at once. Mac settings are the same for every paired phone.
| Section | Settings | Where |
|---|---|---|
| Display | All displays, the main display or a chosen one; then the area: Full display, Window⦠(click a window; the mapping follows it) or Region⦠(drag, move or resize a rectangle; optionally keep the phone's aspect ratio). Tint outside the region dims the rest while the phone is connected | Mac and phone (the window and region are picked on the Mac; the phone can reset the region to the full display and toggle the tint) |
| Pen | Pen (absolute) or Mouse (relative, with its own speed and acceleration); side button: right click, middle click, eraser while held, double click or none | Mac and phone |
| Pressure | Tip feel (soft to firm), click threshold, full pressure at; try it on the Test pad (Mac) | Mac and phone |
| Gestures | Pointer and scroll speed; Smart Zoom (follow macOS, on, off); pinch to zoom, rotate, three-finger drag and four-finger gestures on or off | Mac and phone |
| Surface | Background (black, dark grey, light), marker opacity, centre marker on or off; the corner ticks and dimmed margins are always shown | phone only |
| Fingers and pad | Finger mode, finger pressure, palm size, pad orientation | phone only |
The phone draws the outline of the area that maps onto the Mac and dims the rest, so a stroke on the phone keeps its shape on the Mac.
scripts/bootstrap.sh # install the toolchain (prints any sudo steps for you)
scripts/doctor.sh # check .NET, workloads, Xcode, Android SDK and devices
scripts/test.sh # Core tests: fast, any OS, no workloads needed
dotnet build PenBridge.slnx
scripts/mac-dev-cert.sh # one-time: stable signing cert, keeps the Accessibility grant
scripts/mac-run.sh # build, sign and launch the menu-bar app
scripts/android-run.sh # build and run on the emulator or a phone- docs/development.md: toolchain setup, building, running and debugging on each platform
- CONTRIBUTING.md: branches, Conventional Commits, pull requests
- docs/architecture.md and docs/decisions.md: the design and the decisions behind it
- docs/specs/: the wire protocol and Core spec, and the Mac server and Android client specs
No phone at hand? tools/PenBridge.SimClient stands in for one: it pairs with the PIN like a real device and streams scripted strokes to the Mac server. It runs from a clone of the repo (see For developers).
scripts/mac-run.sh # launch the server, grant Accessibility, then choose "Pair new deviceβ¦"
# in another terminal, with the PIN from the pairing window
dotnet run --project tools/PenBridge.SimClient -- pair --host 127.0.0.1 --pin <PIN>
dotnet run --project tools/PenBridge.SimClient -- draw circle # or pressure-ramp, tilt-sweep, hover, button-click
dotnet run --project tools/PenBridge.SimClient -- scripts # list every draw scriptOpen a pressure-aware app such as Krita first to watch the strokes arrive.
A paired phone controls your pointer, so PenBridge treats pairing as the front door.
- π Only paired devices can inject input. Pairing uses J-PAKE with the PIN or a one-time QR token, so the secret never crosses the network (ADR-0009).
- π§· No man in the middle. Pairing confirmation is bound to the Mac's certificate, and the phone pins that certificate for every later connection.
- π Everything is encrypted. Control messages go over TLS 1.2+, and every pen datagram is AES-256-GCM with a fresh key per session (ADR-0004, ADR-0013).
- π« No plaintext fallback. Replayed, tampered or stale packets are dropped, and PINs expire after 2 minutes or 3 wrong tries.
PenBridge.slnx
βββ src/
β βββ PenBridge.Core/ platform-free: protocol, crypto, pairing, mapping, gestures
β βββ PenBridge.Mac/ menu-bar server and CGEvent tablet injector
β βββ PenBridge.Android/ client: drawing surface, S Pen, discovery, pairing
β βββ PenBridge.iOS/ placeholder only
βββ tests/PenBridge.Core.Tests/ xUnit v3, runs anywhere
βββ tools/PenBridge.SimClient/ fake phone: pairs and draws scripted strokes
βββ scripts/ bootstrap, doctor, test, mac-*, android-*
βββ docs/ architecture, decisions (ADRs), specs, development
Does it work with Krita or Photoshop? Krita, yes. It's the reference app, and pressure, tilt, hover and the side button from a real S Pen were checked in it during the on-device verification. PenBridge posts standard macOS tablet events, which other pressure-aware apps read too, but Photoshop hasn't been tested.
How fast is it? Measured on a Galaxy S23 Ultra over Wi-Fi in a 30-second scribble (about 56,000 samples), from the phone sending a sample to the Mac injecting it: about 3 ms median and 8 ms p95. For the first sample of a stroke (pen down), about 4 ms median and 14 ms p95. Wi-Fi adds the occasional spike of around 100 ms.
Why Wi-Fi and not USB? Wireless is the point: no cable between you and the canvas. Pen samples are tiny and sent over UDP to keep latency low. A wired mode isn't on the roadmap today.
What about iPhone and iPad? There's an iOS placeholder project, and an iOS client is planned for later, after the Android MVP.
MIT Β© 2026 Paul Ciurea