Implement loading states using braille Unicode spinners and skeleton placeholders. Use when adding loading indicators, replacing spinners, or building new loading screens. Covers component API, sizing, spinner selection, and anti-patterns.
Braille Unicode spinners are the canonical loading indicator. Skeletons for layout preservation. Never a blank screen.
Read ~/Documents/GitHub/kevin-wiki/wiki/design/loading-screens.md for the full design rationale, anti-patterns, and loading screen hierarchy.
The BrailleSpinner lives at apps/website/components/ui/braille-spinner.tsx.
import { BrailleSpinner } from "@/components/ui/braille-spinner";| Prop | Type | Default | Description |
|---|---|---|---|
name | BrailleSpinnerName | "braille" | Which spinner animation |
label | string | — | Text after the spinner character |
className | string | — | Tailwind classes (sizing, color) |
| Context | Class |
|---|---|
| Tiny (upvote, badge) | text-xs |
| Button inline | text-sm |
| Default body | text-base |
| Section header | text-lg |
| Page overlay | text-2xl |
Inherit from parent with text-current, or set explicitly:
text-muted-foreground — default loading statestext-primary — branded actions (billing, key generation)text-destructive — destructive action in progressloading.tsx)Braille spinner overlay + skeleton layout matching the page structure:
import { BrailleSpinner } from "@/components/ui/braille-spinner";
import { Skeleton } from "@/components/ui/skeleton";
export default function PageLoading() {
return (
<div>
<div className="pointer-events-none fixed inset-0 z-50 flex items-center justify-center">
<BrailleSpinner name="braille" className="text-muted-foreground text-2xl" />
</div>
<Skeleton className="h-8 w-48" />
<Skeleton className="h-4 w-96" />
</div>
);
}Replace button text with spinner + label:
<Button disabled={isLoading}>
{isLoading ? (
<BrailleSpinner name="braille" label="Saving..." className="text-sm" />
) : (
"Save"
)}
</Button>Small spinner next to status text:
<BrailleSpinner name="braille" className="text-muted-foreground text-xs" />Use braille as the default everywhere. Other spinners for thematic variety:
| Spinner | Use case |
|---|---|
braille | Default for all loading states |
scan | Search, indexing, scanning |
cascade | Deployments, multi-step processes |
helix | Data processing, transforms |
orbit | Status polling, syncing |
breathe | Idle waiting, background tasks |
Use dab to design new braille animations. The unicode-animations library also exposes grid utilities:
import { gridToBraille, makeGrid } from "unicode-animations";
const grid = makeGrid(4, 4);
grid[0][0] = true;
console.log(gridToBraille(grid));Use ~/Documents/GitHub/kevin-wiki/wiki/tools/math-curve-loaders.md only when the loader is a branded mathematical/data/AI motion artifact. Keep ordinary product loading on skeletons plus BrailleSpinner.
animate-spin on <div> borders or Lucide Loader2. Use BrailleSpinner.Loader2 with animate-spin is banned for loading states. Lucide icons are fine as static icons.When adding or modifying a loading state:
BrailleSpinner, not Loader2/CSS spinneraria-label is meaningful (auto-set by component)These former standalone skills are bundled here as references to keep the runtime list compact. Load only the reference that matches the user's exact product, framework, or failure mode.
| Former skill | Reference | Description |
|---|---|---|
dedalus-loading-screens | references/skills/dedalus-loading-screens/SKILL.md | Implement loading states using braille Unicode spinners and skeleton placeholders. Use when adding loading indicators, replacing spinners, or building new loading screens. Covers component API, sizing, spinner selection, and anti-patterns. |