A More Consistent App: Buzzer Controls, Type Scale & Cleaner Device Cards
We spent this week making the app look like one app again — same controls, same type, same story about your hardware.
You might have noticed the buzzer felt like it came from somewhere else. It did, really — it had grown its own set of hand-built pill buttons in a shade of blue that doesn't appear anywhere else in the app, alongside five arbitrary frequency presets and a duplicate module title stacked under the one the card above already showed. We went ahead and rebuilt it out of the same pieces every other module uses: two sliders and two buttons. Frequency and duration are continuous things, so they're sliders now, and their limits come straight from the module definition instead of numbers typed into the control. One nice detail — the duration slider used to technically allow a full minute of buzzing, which meant every value you'd actually reach for lived in the first sliver of the track. It's clamped to a sensible range now, so the slider is usable end to end. We also fixed a stray timer that could keep running after you hit Stop, or fire after you'd already navigated away.
The system map got a similar reality check. If you had one board running one script, the middle column drew two identical cards side by side, which made it look like you had two boards. A board isn't a peer of the script that runs on it — it's the context for it. So a single-board project now shows one card: the script card, carrying its board underneath ("3 modules" when it's online, and just "offline" when it isn't, since a live module count is something we can only honestly report when we can see the board). Projects with more than one board still get device cards as group headings with their scripts nested beneath, and scripts that broadcast or target several boards sit below the groups and say so plainly rather than pretending to belong to one. There was also a quiet bug where two scripts with the same shape pinned to different boards collapsed into a single entry — that's sorted.
Underneath all of it, we finally gave the app one type scale. The same handful of font sizes used to be declared in two places that happened to agree, with nothing keeping them honest, plus a couple dozen one-off pixel sizes sprinkled through screens like webhooks. Those are gone. The practical payoff shows up in chat: conversation widgets used to render a few sizes smaller than the messages around them, so they read like a tiny separate app wedged into the thread. They now use three sizes that match the conversation — body, secondary, and label — with line heights that actually breathe, and a few leading icons nudged up so they sit right next to the larger text. Collapsed receipts and list rows stay one notch down on purpose; a wall of full-size headlines is its own kind of noise.
None of this adds a button you have to learn. It just means the buzzer behaves like the relay next to it, your one Pi looks like one Pi, and widgets read as part of the conversation instead of an interruption in it.
Small stuff, mostly — but the kind you feel every time you open the app. Thanks for the screenshots that pointed us at it.