DEV Community

RAXXO Studios
RAXXO Studios

Posted on Originally published at raxxo.shop

Why Every RAXXO Tool Skips the Loading Spinner

  • Every RAXXO tool replaces the generic spinner with a placeholder shaped like the real content, so a wait reads as almost instant

  • The rule started with Statusline Builder's live preview panel going blank on every keystroke

  • Three fixed rules run the pattern, match the real layout, hold the last known state when I can, never show motion that carries no information

  • I still use a spinner in exactly one place, and knowing where that place is turned out to be the harder half of the rule

The Blank Half-Second In Statusline Builder

Statusline Builder renders a live preview of the statusline a person is building, updated as they type. Every keystroke, a small piece of terminal UI on the page has to re-render to match the new settings. The first version did the obvious thing. It cleared the preview panel and dropped a spinner in the middle of it while the new statusline recomputed.

The recompute itself was fast. On any normal machine it finished in well under a second. The problem was not speed. The problem was that a blank panel with a spinning icon reads as "something broke" far more than it reads as "something is loading," especially when it happens dozens of times in a row while someone is actively typing. I watched a tester type a few characters, pause, watch the panel flash to empty and back, and ask out loud whether the tool had frozen. It had not frozen. It had just told them, visually, that it might have.

That is the part I had not accounted for. A spinner is a promise that something is happening that you cannot see yet. For a process that takes most of a second, the promise is honest. For a process that takes a fraction of that, the spinner becomes noise, a flicker that interrupts the thing the person actually cares about, which is seeing their own statusline update.

I pulled the spinner out and replaced it with a placeholder shaped exactly like the finished preview, same height, same rough block layout, populated with the last valid render until the new one was ready to swap in. The flicker disappeared. Nobody has mentioned the preview panel since, which is the outcome I actually wanted. A UI element doing its job right does not get talked about.

The Three Rules Behind Every Placeholder

That fix could have stayed a one-off patch to one panel in one tool. Instead I wrote it down as a rule and started applying it everywhere a RAXXO tool shows content that takes a moment to arrive. The rule has three parts, and all three have to hold or I do not count it as done.

The first rule is that the placeholder has to match the real layout. Not a generic box, not a centered icon, the actual shape the content will take, same rows, same rough proportions, same spacing. A placeholder that looks nothing like what replaces it just trades one jarring swap for another. Guessing the shape wrong is worse than no placeholder at all, because now there are two layout shifts instead of one.

The second rule is to hold the last known state whenever the tool has one. Statusline Builder's fix works this way, the panel does not go blank between keystrokes, it keeps showing the previous valid render until the next one is ready, then swaps. This only works when there is a previous state to hold onto, which is most of the time in a tool someone is actively using, and it is the single biggest reason the flicker went away. A cold start, the very first load with nothing to hold, still needs the shaped placeholder from rule one.

The third rule is the one I broke the most before I wrote it down, never show motion that carries no information. A spinning icon tells a person exactly one thing, that time is passing. It does not tell them what is loading, how much is left, or whether it is stuck. A shaped placeholder tells them more just by existing, this is the outline of what is coming, and the moment content is ready it slots into a space that was already the right size, so nothing jumps.

Where I Still Use A Spinner

I want to be honest that this is not an absolute rule against spinners everywhere, because a rule with no exceptions usually means I have not thought hard enough about the edges. I still use a plain spinner in exactly one place across every RAXXO tool, on a button after someone clicks it to trigger an action with no visual result to preview, a download starting, a form submitting, a setting saving.

The reason that spot is different is that there is nothing to shape a placeholder around. A shaped placeholder works because it previews content, a preview panel, a list, a card. A button click triggering a background action has no content to preview, only a state, working versus done, and a small spinner on the button itself communicates exactly that with nothing extra. Trying to force a content-shaped placeholder into that spot would be solving a problem that is not there.

The line I actually draw is about content versus action. Anything rendering content that a person is about to look at gets the shaped placeholder and the held-state treatment. Anything confirming that a click registered gets a small, contained spinner and nothing more. Mixing the two up in either direction is where I have seen this pattern go wrong in other tools I have used, a full-page spinner over what should have been a content preview, or an elaborate skeleton screen around what was really just a save button.

There is a third case that took me longer to place, an action that also changes content once it finishes, downloading a generated file, running a check that then updates a list below it. For those I use both, a small spinner on the button itself so the click feels acknowledged right away, and the held-state treatment on the content area it will eventually update, so the two pieces of feedback answer two different questions at once, did my click register, and has anything actually changed yet. Splitting those two questions apart, instead of using one loading state to answer both, is the part of this rule that took the most trial and error to get right.

Rolling It Out Across Five Tools

Once the rule existed, I went back through every RAXXO tool and found every spot doing the old blank-and-spin pattern. Git Dojo's exercise panel got the same treatment as Statusline Builder's preview, a shaped placeholder that matches the terminal output layout, holding the previous exercise's render until the next one is parsed and ready. OhNine's menu bar view, which checks and displays Claude usage status, now shows the last known numbers, slightly dimmed, instead of clearing to a spinner every time it refreshes in the background. Claude Blueprint's install checklist keeps its previous state visible while a step re-validates rather than blanking the whole list.

The pattern held up everywhere I applied it, which told me it was a real rule and not a fix that happened to work once. The part that took actual work was not the code, holding a previous value and swapping it is a small, mechanical change in most component frameworks. The work was going tool by tool and honestly separating the content spots from the action spots, because getting that split wrong in either direction produces a worse result than doing nothing at all.

Claude Mythos was the one place the rule almost did not fit. It renders a longer analysis after a person submits a design, several seconds of real work, not a fraction of a second like Statusline Builder's preview. A held-state placeholder made no sense there, because there was no previous analysis of this specific design to hold onto. Rather than force the pattern where it did not belong, I kept a plain progress indicator for that one screen, but made it honest, a short line of text describing what stage the analysis was actually in, not just a generic spinner claiming something was happening. The rule was never "no spinners anywhere." It was "no motion that carries no information," and a labeled progress state satisfies that just as well as a shaped placeholder does, for the specific case where there really is nothing to preview yet.

It also changed a habit for anything new I build now. Before I write the loading state for a new piece of a tool, I ask which of the two categories it falls into, content the person is about to look at, or an action they just triggered, before I write a single line handling the wait. That one question upfront has saved me from redoing loading states after the fact more than once, because it is a much harder question to answer honestly once a spinner is already sitting there looking fine at first glance.

The other thing that changed is how I think about the design system that ties five RAXXO tools together. A shared placeholder pattern is not a visual rule, it does not live in a color token or a spacing scale, but it is exactly the kind of consistency a person feels across tools without being able to name it. Open Git Dojo, then OhNine, then Statusline Builder, and the wait always behaves the same way, holds what it can, shapes what it cannot, never flickers for no reason.

Bottom Line

The fix started as one panel in Statusline Builder going blank on every keystroke and a tester asking if the tool had frozen. It had not frozen, the spinner had just made a fast, ordinary process look uncertain. Replacing it with a placeholder shaped like the real content, holding the last known state whenever one exists, and cutting motion that carries no information turned out to be a rule worth applying everywhere, not a one-off patch.

It is not a rule against spinners entirely. A spinner still earns its place on a button confirming a click registered, where there is a state to show and no content to preview. The actual discipline is telling those two situations apart before writing the loading state, not after. Since I rolled this out across every RAXXO tool, the same instinct that shaped the kill switch every RAXXO tool ships with shows up here too, small, boring, and there so a wait never reads as something broken.

Top comments (0)