A blank preset is still a button

Fidelia’s CarPlay screen has four preset buttons. If you have filled only two of them, the other two still draw — dimmed, inert, occupying their exact space.

That costs us something. It would be less code and a cleaner screen to draw only the presets that exist. We draw the empty ones because a car radio’s blank preset is a visible dead button, not a gap that shifts the others under your thumb at speed. The person reaching for preset 3 is watching the road. Their hand already knows where 3 is. If 3 slides left because 2 was never filled, we have built something that photographs better and behaves worse.

That one decision is most of how I think about software.

Software has no manufacturing tolerance, and that is the problem

A physical control tells the truth about itself for free. A knob has mass, so it cannot move faster than your hand. A detent clicks whether or not anyone wrote code for it. A button stays where it was bolted. You get all of that from the material, and you get it consistently, because the tooling that made the first one makes the ten-thousandth one the same.

Software gets none of it. Every property a physical object has by default, an interface has to be given deliberately, one at a time, and then defended against every future change. Nothing in a UI toolkit insists that an object remain the same object while it moves. Nothing stops a list from stuttering. Nothing makes a control keep its position because a neighbour is missing. Those are all things you must decide to pay for.

So the useful discipline is to build software as though it were being manufactured: fixed positions, honest timing, behaviour that survives being used quickly by someone who is not looking at it.

Timing is a material

The clearest place this shows is motion, and the test is simple: does the object persist?

In Fidelia’s album wall, clicking a cover opens that album. The cover flies from its place in the grid to its place on the album page. The naive way to build that is a cross-fade — the grid dissolves, the page resolves. It reads fine in a screenshot and it is wrong, because real objects do not dissolve into each other. They travel.

So the cover travels. And the detail that actually makes it work is not the spring curve, it is the bitmap: the flying cover carries the wall cache’s own full-resolution decode, and the album page shows that same bitmap from its very first frame. Not a re-decode. The same pixels, handed across. Get this wrong and the artwork re-decodes on the main thread while the flight is still in the air, and you get a stall in the middle of the motion — which we measured, which is why the code is written the way it is now.

A hitch of a few frames is not a rendering defect. It is the object briefly admitting it was never really an object.

Skeuomorphism is a constraint, not a texture

The word got ruined by a decade of stitched leather and torn paper, and those deserved to go. But the useful idea underneath was never decoration. It was a promise: if this thing resembles something, it will behave like that something.

Which means the resemblance is the cheap part and the obligation is the expensive part. If a row of presets refers to a car radio bank, then it inherits the bank’s physics — fixed slots, stable positions, the number reading first because that is how your eye finds it. You do not get to keep the metaphor where it flatters you and drop it where it costs you. A metaphor obeyed only when convenient is worse than no metaphor, because it teaches the hand a rule and then breaks it.

That is the test I apply. Not does this look like a device but does this keep the promises a device would have made.

The instrument test

Fidelia’s track lists are not built in SwiftUI. They are NSTableView, with all the extra work that implies: column visibility persisted through the table’s own autosave, drag-to-reorder that engages only when the sort order makes reordering meaningful, headers you right-click to show and hide columns, resizing that shares width across columns instead of letting the last one overflow.

We could have written far less code. But a track list is the surface a person drags through ten thousand rows on, and it has to hold at speed — every row, every scroll, no exceptions. A list that stutters is not a list. It is a picture of a list.

This is the line between an interface and an instrument. An interface has to be understood. An instrument has to be operated — often quickly, often by someone who is looking somewhere else, often by a hand that has learned where things are and is no longer checking. Instruments earn that trust by being boringly consistent about position, timing and state, thousands of times, and they lose it permanently the first time they are not.

Where this comes from

We did not arrive at this from design theory. We arrived at it from hardware.

For years, under the Krekeltronics banner, this studio built devices and the software that sits next to them — the electronics, the firmware, and the companion apps that make a piece of metal feel like something. That work has a property software alone does not: the object is right there in the customer’s hand, keeping its own promises perfectly, at all times, for free. Your software is being graded against it every second, and it is not a generous grader. Nobody thinks the app is fine, the knob is just better. They think the product is cheap.

I wrote elsewhere that the hardware was the easy part, and the reason is related. The schematic is finished months before the product is, because everything that makes a device feel like a device turns out to live in software: the update that cannot brick a unit, the latency budget where a marketing adjective meets a number, the recovery when the hardware wakes up later than the computer did.

Fidelia now lives on the other side of that same handshake. It is downstream of everyone else’s hardware — interfaces, DACs, dongles, head units — and the standard has not moved. The DAC in the rack is a real object with real mass. The app driving it has to be at least as solid, or the whole chain feels like a toy with an expensive component in it.

So: the empty preset still draws. The cover travels instead of dissolving, carrying its own pixels so it never stalls mid-flight. The table is a real table. None of it is the shortest path, and all of it is the same decision, made over and over — that the thing in front of you should behave like an object, because that is the only way it will ever feel like an instrument.