Skip to main content

Loading & Empty States

GospeLib uses an optimistic UI philosophy — the interface should always feel immediate, even when data is in transit. When loading is unavoidable, it must be beautiful and informative. Errors are gentle and recover gracefully.

Core Philosophy

"Never show a spinner where a skeleton will do. Never show a skeleton where cached content will do. Never show cached content where fresh content is already available."

Priority waterfall:

  1. Cached content (instant, from SQLite/MMKV)
  2. Optimistic update (immediate UI change, reconcile on server response)
  3. Skeleton (if no cache exists)
  4. Spinner (never for content — only for discrete actions like "saving note…")

Scripture Page Skeleton

When a chapter loads without cached content:

Shimmer Pattern

ElementSkeleton Treatment
Chapter headerCentered block, corpus color at 15% opacity
Verse numbersSmall square pulses at left margin
Scripture textLength-accurate line blocks matching expected content layout
Footnote indicatorsNot shown in skeleton state

"Length-accurate" means the skeleton lines match the approximate line count and line widths of the actual content. This prevents layout shift when content appears.

Animation

@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}

.skeleton-line {
background: linear-gradient(
90deg,
var(--color-tan-100) 25%,
var(--color-tan-50) 37%,
var(--color-tan-100) 63%
);
background-size: 200% 100%;
animation: shimmer 1.5s ease-in-out infinite;
}

The shimmer uses tan tones (not gray) to match the warm paper surface. It should feel like light moving across paper, not a digital loading indicator.

Search Progressive Loading

PhaseTimingContent
Instant0msText index results (Typesense) — fast fuzzy matches
Fast200–500msGraph-enriched results (FalkorDB) — cross-references, topics
Streaming500ms+AI semantic results — stream in as they're computed

Results from each phase append to the list. No full-screen loading state — results appear progressively as they become available.

AI Token Streaming

AI responses (passage explanations, study questions) stream token-by-token:

PropertyValue
CursorSubtle blinking bar at the end of streamed text
AnimationEach token fades in (opacity 0→1, 60ms)
Paragraph breaksRendered immediately when detected
CitationsScripture references become tappable links as they complete
InterruptionUser can tap "Stop" to halt generation

The One Loading Animation

GospeLib has exactly one loading animation — a breathing app icon:

PropertyValue
IconGospeLib logo (simplified)
AnimationGentle scale pulse (0.95→1.05→0.95)
Duration2s per cycle
EasingsmoothInOut
UsageFull-page loading only (app launch, deep link resolution)

No other spinners, progress circles, or animated indicators. Every other loading state uses skeletons or progressive content.

Error States

Philosophy

"Errors are amber, not red. Inline, not modal. Recoverable, not terminal."

PrincipleImplementation
Amber, not redWarning color #C47A2A — red is reserved for destructive confirmations only
Inline, not modalError messages appear contextually near the failed action
RecoverableEvery error message includes a recovery action
BriefOne sentence max. Technical details in expandable "Details" section

Error Message Pattern

[Amber ⚠ icon] [Brief message] [Recovery action button]

Example:
⚠ Couldn't load cross-references. [Try again]

Offline Errors

ScenarioMessageRecovery
No network, cached content availableNo indicator (reads from cache silently)Auto-sync when reconnected
No network, no cache"You're offline. This content will load when you reconnect."Auto-retry on reconnection
Sync conflict"Your note was edited on another device. [Keep this version] [Keep other]"User choice

Success Confirmations

"Wordless whenever possible."

ActionConfirmation
Highlight appliedColor washes in (visual-only, no toast)
Bookmark setIcon materializes with micro-animation
Note savedCheckmark briefly appears on the note card
Download completeProgress bar fills, then fades away

No toast messages for routine actions. The animation is the confirmation.

For significant actions (export complete, account changes), a brief inline message appears for 3 seconds then fades.

Empty States

When a section has no content, the empty state follows a consistent template:

Template

ElementContent
IllustrationGentle line-art illustration (matching the icon set style)
HeadingDescriptive, not apologetic ("Start your study journal" not "No entries yet")
BodyOne sentence explaining what this section is for
CTAPrimary action button to create first item

Empty State Examples

SectionHeadingCTA
Journal"Start your study journal""Write your first entry"
Collections"Organize your study""Create a collection"
Bookmarks"Save passages for later""Bookmark a verse by double-tapping"
Highlights"Mark what matters""Highlight a verse to begin"
Search history"Find anything in scripture"(Search field focused automatically)