Building for One · Part 2 of 3
A Control Center for an Audience of One
This is the audience of one up close: the control center I built for one desk, the widgets it ended up with, and the hardware that fought me the whole way.
In the first article of this series, I made the case that a coding agent has lowered the cost of building software far enough that it is now worth building tools for an audience of one. This is the audience of one, up close, and the tool I built for it. If you want the argument, it is in that first article; this piece is the build itself, the hardware that fought me and the dead ends. What the tool grew into, widget by widget, has a full description of its own elsewhere in the series.
To see the problem it solves, picture the desk. I run three monitors. A Samsung G9, a 49-inch ultrawide, sits across the bottom, and two Dell 27-inch displays sit side by side on top of it, so the working area is one enormous curved screen with two more stacked above it. That is a lot of real estate, which is wonderful right up until I am hunting for one window among the dozens scattered across it, or dragging an application from the far end of the ultrawide up to a monitor two screens away. A Corsair Xeneon Edge touch strip sits below all of it. The whole app is really an answer to a single question: how do I command that much display without swimming through it by hand.
The window sprawl is only half of it. The harder problem is how often the work itself changes. On a given day I switch context sometimes every thirty minutes, all day long. I move up and down in altitude, between executive, operator, and builder, and I move sideways across the work as well: sitting in meetings, building agents and workflows for several different client teams, working on my own tooling, synthesizing documents people send me, and writing my own. Each of those wants a different set of applications, open and arranged its own way. Resetting the whole workspace to match whatever I am focused on right now, and doing it fast, saves a real amount of time and cognitive load. That is the reason a single tile that tears down one context and rebuilds another is the widget I lean on hardest.
The app is called Desk Control Center (so creative I know), a grid of small widgets, each one a control for something I touch all day. Everything on it is a shortcut to something I would otherwise do with a keyboard, a menu bar, or a trip to another window: placing the current window on a specific monitor, launching a pinned app, skipping a track, running a timer, watching how much of my Claude budget is left. The tile I described a moment ago, the one that tears down a context and rebuilds it, is Work Sets; the one my eyes return to most is App Control Center, a live grid of every app I have running and its open windows that turns “which of my forty windows was that in” into a glance and a touch. What each widget is and why it exists has a full description of its own elsewhere in the series.
It is a native SwiftUI app, built with Command Line Tools and Swift Package Manager, no Xcode anywhere in the loop. That constraint is itself a small artifact of the era: a decade ago the sane way to write a Mac app was to open the official IDE and stay inside it, and here the whole thing builds from a shell script.
None of that is what made the project interesting to build, though. A grid of widgets is a grid of widgets, and with an agent doing most of the typing, assembling the ordinary parts went quickly. What I actually remember are three fights with the hardware. Two of them traced back to the same fact: this is a real, always-on piece of hardware bolted to my desk rather than a window on an ordinary screen. The first was getting the panel to talk to me at all; the second was learning that a surface which never turns off is unforgiving of wasted work. The third was a different kind of trouble, an input device that lies to the Mac about what it is. Those are the stories worth telling.
The hardware did not want to be programmed
The good part of this panel is that it responds to touch. The bad part is that it exposes touch through no documented interface at all. The first dead end was the obvious one. Corsair ships a vendor ID, 0x1B1C, and I assumed the touches came from there. They do not. That ID is only the monitor’s vendor-defined control channel, the thing that sets brightness and reads the panel’s own settings. The actual touch stream comes from a completely separate controller baked into the display, a WCH part reporting as vendor 0x27C0, product 0x0859. You would never guess that from any documentation, because there is none. What made it tractable was that two people had written open-source drivers for this exact panel, and the agent could read both, cross-check them against what the device actually emitted, and reconstruct the recipe.
And it is a recipe, in the sense that every step is load-bearing and the thing stays dead if you get one wrong. Match on that vendor and product ID. Schedule the HID manager on the main run loop specifically, because input-report callbacks are only delivered through run-loop scheduling and silently never arrive on a dispatch queue. Open the device with a seize, so that macOS does not also try to drive the system cursor from the same touches, which is what made early taps warp onto the wrong display. Then register a callback for the raw input report and decode it by hand.
The report is seven bytes. Byte one is the tip switch, nonzero when a finger is down. Bytes two and three are the X coordinate, little-endian, running zero to 16383. Bytes four and five are Y, zero to 9599. That is the entire vocabulary the hardware offers, and everything the panel does is built back up from it.
Turning that into clicks required one more compromise that I found genuinely funny. macOS has exactly one system cursor. To make a touch land as a click on the right pixel, the app borrows it: on finger-down it saves where the cursor was, freezes the physical trackpad, and warps the cursor to the mapped point on the Edge; on finger-up it puts everything back. Because there is only one cursor and one finger at a time, a single gesture has to commit to being exactly one thing. A stroke that lifts within eight points is a tap and becomes a left click. A stroke that travels past eight points is a scroll and starts emitting scroll-wheel events under the finger. A stroke that sits still past 600 milliseconds is a long press and fires a right click to open a context menu. That is a real trade. I gave up finger swipe-paging and drag-to-reorder to get reliable scrolling and menus, and for a support surface that was the right side of the deal.
An always-on surface punishes every wasted cycle
The panel is the full-screen window on a display that never turns off and never gets covered. That property turns out to be the whole personality of the project. On an ordinary screen, a costly view only runs while it is visible; here every view is always visible, so any inefficiency runs nonstop.
The first version had a bug I did not see coming. The app’s top zone lays widgets out in a masonry grid, and the drag-to-reorder logic needed to know where each cell had landed. It got those frames through SwiftUI’s preference system and wrote them into view state. Writing view state invalidated the view, which re-ran the layout, which re-measured the frames, which wrote the state again, about thirty times a second, forever. On a normal screen you might never notice. Here the zone is always visible, so it pinned a CPU core from the moment the app launched. The consequence was the part that actually hurt: a saturated main run loop stopped servicing display-change notifications, so when I unplugged and replugged the Edge, the app never noticed until I restarted it. The fix was to stop routing those frames through view state at all, since only the drag gesture ever reads them. After that the layout settles in one pass, and the profiler went from 338 busy samples to three.
The second one was quieter and more embarrassing. The app idled around 48 percent CPU, sometimes spiking over 100, doing nothing. Profiling put almost half the main thread inside Core Animation’s commit path, driven by a handful of decorative animations that were set to repeat forever: an ambient wash behind the music widget, a loading shimmer, a pulsing border. On a panel that appears and disappears, those cost nothing. On a panel that is on screen twenty-four hours a day, they never stop rendering. Making them static, and dropping one perpetually animating weather glyph, took idle CPU to about four percent and let the main thread finally park and wait for work. The lesson the hardware kept teaching was the same one: on a surface that is always present, there is no idle to hide waste in.
The mouse pretends to be a keyboard
The third fight came from wanting the window placements I use most under my hand instead of on the panel, so I bound them to the twelve side buttons on my Razer Naga. Reusing the window-moving machinery took an afternoon; the trigger was the whole problem. The Naga does not show up to the Mac as a mouse with extra buttons. Those twelve buttons register as a keyboard typing the number row, and at the input layer a press of side button three cannot be told apart from me typing a 3 on my actual keyboard.
That rules out both of the easy approaches. Seizing the device the way the panel seizes the touchscreen would capture the buttons, but the Naga is also my pointer, so grabbing it kills the cursor. Swallowing the number-row keys everywhere would stop the buttons from typing digits, and stop my keyboard from typing digits along with them, which breaks ordinary typing across the whole machine. Neither is a trade I would accept on a device I use all day for real work.
The way through is to watch the mouse directly and correlate. The app listens to the Naga as a mouse, recognizes when a keystroke actually originated as a side-button press on that device, and only then suppresses the matching number-row key, turning it into a window move instead of a digit. Real typing never produces that coincidence and passes through untouched. It is a narrow, slightly paranoid piece of code, and it is what it costs to make an input device that misrepresents its own identity behave the way I want.
The honest part is the dead ends
Not everything I wanted was possible, and the limits were often more interesting than the wins. Spotify’s developer terms permanently refuse to return the tracks of a playlist at my access tier, so the “up next” view had to be rebuilt from the playback queue instead. Our corporate Okta push sends its number challenge only to a phone, with no signal the Mac can see, so approving a login from the panel is simply off the table. macOS will let an app jump between virtual desktops but will not tell it which desktop is currently active, which makes the panel an emitter and never a mirror. Writing those down honestly is part of the fun, because at this scale nobody is going to pretend the gadget does more than it does. There is also a small discipline hiding in the constraints: with no Xcode there is no XCTest, so the touch parser is a pure function that a plain test harness drives with synthetic seven-byte buffers, no hardware required.
None of this was important, and that was the whole freedom of it. I could over-build a right-click menu for a touchscreen almost nobody owns, spend an afternoon shaving a CPU core off an idle animation, and answer to no one but myself about whether it was worth it. That is a strange and genuinely good position to get to build software from, and until recently it was one almost no single person could afford to reach.