This page covers the perceived-performance design of every wait state in the DomiDo Progressive Web App. Perceived performance — how fast the application feels — is often more important than measured performance. A three-second wait with rich feedback feels faster than a one-second wait with a blank screen. Every wait state below has a defined feedback pattern, a duration band, and an escape route. The application's feedback patterns map onto the standard perception thresholds, the fifteen significant wait states each receive a specific treatment, the skeleton-versus-spinner choice follows one rule, and progressive content loading (gallery images, 3D models, assembly instructions) avoids the worst kind of dead time at the moments where users are most likely to abandon.
Below one hundred milliseconds an interaction feels instantaneous; transitions require no feedback. Between one hundred milliseconds and one second a subtle transition or skeleton placeholder fills the gap. Between one and five seconds a progress indicator with context is required. Between five and ten seconds the indicator must include estimated time. Between ten and thirty seconds the indicator must include multi-stage progress and an explanation. Beyond thirty seconds the indicator must provide rich feedback with intermediate results, an estimated completion time, and clear value to the user. Beyond two minutes the operation is treated as background processing — the user is told they can leave the screen and will be notified.
The application has roughly fifteen significant wait states.
File upload to object storage takes five to sixty seconds and uses a determinate progress bar showing percentage, megabytes, and the cancel button — strongly specified, low gap. Twelve-stage pipeline processing takes five to one hundred and twenty seconds and uses the twelve-stage vertical stepper with named stages, green checkmarks for completed stages, a spinner for the current stage, Server-Sent Events streaming updates, and a polling fallback; it is the strongest wait-state implementation in the application. AI frontal image generation takes fifteen to ninety seconds and uses a staged animation with an elapsed-time counter and "fun fact" content for waits exceeding thirty seconds, plus provider-fallback messaging when the primary provider fails and the next provider takes over. Per-projection generation in the AI mode takes fifteen to forty-five seconds per angle and uses the same staged-progress pattern with elapsed time and fun facts. 3D model generation takes thirty to one hundred and twenty seconds and uses a countdown timer with stage descriptions and the eight approved projection thumbnails displayed as a reminder of what is being assembled.
The gallery feed initial load is below five hundred milliseconds when cached and below two seconds on a fresh fetch; it uses a two-column skeleton grid matching the card layout with the standard shimmer animation. Gallery search results are below two seconds for text, below five seconds for voice, and below three seconds for image, with a skeleton results grid and the active query echoed at the top. The 3D viewer initial model load is variable depending on model complexity and uses a branded loading screen with progress, a pre-rendered static image as the poster, and a transition from static to interactive once the GLB is parsed. The Stripe checkout session creation takes one to three seconds and uses a branded transition screen with the DomiDo logo and "Connecting to payment..." text — a generic spinner would feel inconsistent. Page navigation is below three hundred milliseconds in nearly all cases and requires no additional feedback beyond the platform-native transition.
Cart add is below five hundred milliseconds and uses an optimistic update: the button shows a checkmark and "Added", the cart badge increments, the network call runs in the background, and the change reverts with a toast on failure. Social actions (like, follow) are below five hundred milliseconds and update optimistically — heart fills, follow button switches to "Following", counts adjust immediately, with revert on failure. The admin dashboard load is one to five seconds total with progressive widget loading: metric cards load first with their skeletons, then tables, then charts, so the dashboard is never entirely blank. Assembly viewer offline caching is variable depending on package size and uses a "Saving for offline..." indicator with progress. The AI provider cascade can take up to one hundred and twenty seconds total across providers plus thirty seconds for each fallback, with staged progress and explicit "Trying alternative service..." messaging between providers; full-cascade exhaustion shows "AI services temporarily unavailable, try again later" with no credit deduction.
Skeletons fill content slots where the layout is known: gallery feeds, design and product details, order lists, design lists, comments, admin tiles, cart, and infinite-scroll appends. Spinners replace button labels during submission and centre on filter or sort application; they appear inside the 3D viewer's branded load and at the top of pull-to-refresh. Image uploads use a linear progress bar rather than a spinner. Settings load instantly from local cache. Skeletons match the target component's radius, the shimmer is forty per cent of the element's width with a one-and-a-half-second sweep, text skeletons are twelve pixels for body and sixteen for headings, image skeletons match the target dimensions, and skeletons cross-fade to real content over three hundred milliseconds.
Gallery images use a blur-up technique: a twenty-by-twenty-pixel blurred placeholder appears immediately as the card background while the full-resolution image loads. Images lazy-load with an intersection observer that pre-loads two hundred pixels before the card enters the viewport. The content delivery network resizes images to exactly the dimensions needed at the current viewport so a phone never downloads a desktop-sized asset.
3D models use Draco compression — typically fifty to eighty per cent file-size reduction. Three level-of-detail meshes (low under ten kilobytes, medium under one hundred kilobytes, high under five hundred kilobytes) load progressively. A pre-rendered static image displays immediately as a poster while the GLB streams in. A header-based pre-fetch starts the GLB download before the React Three Fiber component mounts. Assembly instructions pre-load three steps ahead so the Next button always feels instant. The complete model is segmented at pipeline time into per-step geometry chunks so the viewer does not have to load every block before step one. Ghost blocks (showing where the next block goes) use GPU instancing to avoid per-block draw calls, ensuring thirty or more frames per second on mid-range mobile for models up to five hundred blocks.
Likes, follows, and Add-to-Cart update optimistically. Comments display immediately for the author with a quiet "Posting..." indicator; if moderation flags the comment it gains an "Under review" badge rather than vanishing. Unlikes, unfollows, and remove-from-collection apply locally and the server commit waits for the undo window to expire so an accidental action is reversible. Optimistic updates carry a local mutation identifier that reconciles with the server response.
The twelve-stage stepper is the strongest wait state because the user sees stages completing. Stages complete at uneven rates — some take a second, others ten — which can create a sense of unpredictable progress. The screen mitigates this by showing per-stage estimated time remaining and a steady global percentage that smooths between stages. For waits longer than thirty seconds the screen surfaces fun-fact content about blocks and assembly, replacing dead time with engagement.
Search inputs debounce two hundred and fifty milliseconds before firing the query. Skeleton results appear immediately on submission so the user sees the layout. Voice search displays a real-time transcript next to the waveform so the user can correct the query before submission. Image search shows the cropped query thumbnail above the results.
The application is a Progressive Web App. The Assembly Viewer caches its model and instructions for offline use; the cache state is exposed on the design (a small "Available offline" indicator). Other surfaces show context-specific offline screens — the Cart says "Your cart is saved", the Gallery says "Load cached designs" with a list of recently viewed items, and the Account says "Sign-in required when back online" if the session has expired.
Every operation has an explicit hard timeout. AI image generation times out at one hundred and twenty seconds; 3D model generation at one hundred and eighty; pipeline processing at three hundred; the Stripe checkout session at thirty minutes; file uploads at one hundred and twenty seconds; the Server-Sent Events connection at six hundred seconds with transparent reconnection; the third-party logistics submission retries silently for up to twenty-four hours. At fifty per cent of the timeout the elapsed-time counter appears; at eighty per cent a warning message tells the user it is taking longer than usual; at one hundred per cent the recovery actions surface. A spinner never appears indefinitely without time context.