Skip to main content
← Back to Docs

Performance

Instant navigation and zero splash screen delays.

What changed

Previously, navigating between pages showed a full-screen splash screen with a progress bar that could block the UI for up to 8 seconds. Now every page loads instantly with skeleton placeholders while data fetches in the background.

Route Progress Bar

A thin gradient bar at the top of the screen gives immediate visual feedback when you click a link. It starts animating instantly and completes when the new page renders — similar to YouTube and GitHub.

Skeleton Loading States

Every major page now has a dedicated loading.tsx file that renders a lightweight skeleton matching the page layout. This means:

  • Notable people directory — grid of placeholder cards
  • Home (/home) — AppShell layout: sidebar, feed column (stories, profile card, widgets), docked Dayze Agent + mobile bottom nav
  • Your People (/[handle]/people) — desktop master–detail: shimmer grid + detail panel skeleton
  • Calendar, Insights, Reels, Timeline — same AppShell chrome with route-specific main column placeholders
  • Movies — poster-ratio grid placeholders
  • Profile pages — avatar, name, and section blocks
  • Admin, Settings, Map, Saved, Explore, chat — all covered
  • Wallet, Inventory, Businesses, Analytics, Playbook — shared ModulePageSkeleton

Intent prefetch

Hover, focus, or touch on sidebar and mobile bottom-nav links warms the route JS chunk and SWR data before you navigate — repeat clicks feel instant.

Load speed tracking (admin)

Superusers can open /admin → Performance to see per-route shell-ready times (ms until the route clears its loading gate), bounce-risk bands, and session aggregates. A summary strip also appears on the admin System Overview.

Bounce-risk bands: <400 ms low · <1 s OK · <2.5 s high · ≥2.5 s critical

Netlify Lighthouse (Best Practices)

Deploy badges on Netlify run Lighthouse on / after each production build. A Best Practices score of 0 in the UI often means the category failed to compute (null → 0), not a literal zero — open the deploy report for details.

  • Anonymous visitors no longer trigger /api/user/onboarding 401s from growth nudges.
  • Landing search chips use first-party people JPEGs under /assets/images/people/ instead of Wikimedia CDN URLs.
  • Production browser source maps are enabled for Lighthouse source-map coverage.

Minimal inline splash

Dayze uses a single inline HTML splash — colored crescent mark with a soft pulsing glow — that covers the pre-hydration gap. No wordmark or fake progress bar on first paint. It is dismissed as soon as React mounts — typically under 1 second. A JS timeout fallback auto-hides it even if hydration is slow. Route transitions may still show the legacy full loader for A/B (`lib/ui/page-loader-variant.ts`).

Pages with loading skeletons

/home
/calendar
/insights
/reels
/people
/[handle]/people
/movies
/animals
/books
/companies
/places
/dome
/map
/timeline
/saved
/admin
/explore
/polaris
/settings
/wallet
/inventory
/businesses
/analytics
/playbook
/share
/time
/people/[slug]
/movies/[slug]
/animals/[slug]
/books/[slug]
/companies/[slug]
/places/[slug]

Scalable client cache

Small bootstrap keys (user id, navbar profile) stay in localStorage for instant paint. Large lists—Your People, events—persist in IndexedDB (50MB+ quota) so power users with thousands of contacts do not hit storage limits.

Cache-first data (SWR persist)

On repeat visits, Home, Your People, and key lists hydrate from persisted SWR cache while auth and Supabase revalidate in the background. A lightweight session bootstrap (dayze_bootstrap_user) paints the shell immediately without waiting for getUser().

  • usePeople / useEvents — loading skeleton only on first unresolved fetch
  • AppInitProvider — prefetches people, events, and profile after sign-in
  • Admin console — AdminPageSkeleton instead of full splash; 1h superuser gate cache
  • useFastAuth — bootstrap shell on home, people, person profiles, wallet, share, analytics, settings, time, inventory, businesses, saved, playbook, calendar, insights, reels, timeline
  • fetchPeopleForUserGuarded — session memory + retry on false empty; merge mode freezes catalog snapshot
  • IndexedDB → SWR rehydrate — non-empty people/events appear in hooks immediately; empty/missing lists fetch fresh data (avoids false RLS-empty cache)
  • isProfilePending — onboarding modals wait for profile fetch; bootstrap stores birthday for repeat visits
  • Idle prefetch — top nav route chunks warm during browser idle time after cache hydrate
  • Settings, finance, replies — unified useFastAuth; replies use 5-minute session cache
  • Inventory & business lists — 24h localStorage page-list cache for instant repeat visits

Maintainer reference: docs/PERFORMANCE.md in the repo.

  • Next.js App Router loading.tsx convention for Suspense boundaries
  • RouteProgressBar — CSS-only animation, no JS timers during transition
  • LoadingContext — dismisses the inline splash on hydration
  • Inline HTML splash — minimal mark + glow; auto-dismissed on load + JS fallback
  • LoadingSkeletons.tsx — Shimmer placeholders: AppShellPageSkeleton, HomePageSkeleton, UserPeoplePageSkeleton, route-specific content skeletons
  • Client auth loading on Home, Calendar, Insights, Reels, Timeline reuses the same skeletons as each route's loading.tsx
  • Home console guardrails — supported Open-Meteo fields only, non-throwing referral stats, non-406 daily check-in reads, direct Supabase Storage avatar loading, and best-effort service-worker cache writes