About this animation
A React Native loader animation can communicate active work without relying on another spinning ring. This Skia orb continuously blends two fluid colors through a warped noise shader, surrounds them with a breathing halo, and settles into a softly drawn completion mark. Use it for account setup, synchronization, content preparation, analysis, or any wait that deserves a focused full-screen moment. A UI-thread frame clock drives the fluid, while one completion value slows the motion, calms the gradient, shrinks the orb, changes the status copy, and reveals the check. Customize the palette, labels, badge, speed, turbulence, proportional size, background, fonts, and completion callback, or call complete and reset through the forwarded ref.
When to use it
- Show progress during setup or synchronization.
- Create a focused loading state for analysis or preparation.
- Transition from active work to a completed state.
- Match a loader to a custom palette and status message.
A two-color fluid loader that continuously swirls, then settles into a softly drawn completion mark.
How it works
- The component measures its own container with
onLayout, positioning every layer as a fraction of that local width and height. - A five-octave value-noise shader applies two levels of domain warping, producing broad, continuous patches instead of hard bands.
- A
useFrameCallbackclock updates on the UI thread. Onedoneshared value simultaneously slows the clock and blends the fluid toward a calm gradient. - The orb is clipped to an antialiased Skia circle, while a separate blurred circle creates the breathing halo and a radial gradient adds the highlight.
- Completion springs the orb smaller, crossfades the status copy, and trims a rounded Skia path from
end={0}toend={1}.
Install
npx expo install @shopify/react-native-skia react-native-reanimated react-native-workletsOn web, copy CanvasKit into the public directory and load it before mounting the component:
npx setup-skia-web publicimport { LoadSkiaWeb } from '@shopify/react-native-skia/lib/module/web';
await LoadSkiaWeb({ locateFile: () => '/canvaskit.wasm' });Usage
import LiquidOrbLoader from './LiquidOrbLoader';
export function LoadingScreen() {
return <LiquidOrbLoader />;
}Use a palette and the imperative controls to adapt the pattern:
import { useRef } from 'react';
import LiquidOrbLoader, {
ORB_PALETTES,
type LiquidOrbLoaderRef,
} from './LiquidOrbLoader';
export function LoadingScreen() {
const loaderRef = useRef<LiquidOrbLoaderRef>(null);
return (
<LiquidOrbLoader
ref={loaderRef}
colors={ORB_PALETTES.lagoon}
label="Preparing your workspace"
completeLabel="Ready"
badge="SYNC"
speed={0.85}
turbulence={1.2}
size={0.5}
onCompleteAnimationEnd={() => continueToWorkspace()}
/>
);
}The forwarded ref exposes complete() and reset().
Props
| Prop | Type | Default | Description |
|---|---|---|---|
colors | { a: string; b: string; glow: string } | ORB_PALETTES.ember | Two fluid colors and the halo color. |
label | string | 'Scanning your accounts' | Status text under the orb. |
badge | string | 'BETA' | Small uppercase pill; hidden when empty. |
speed | number | 1 | Swirl speed multiplier. |
turbulence | number | 1 | Swirl detail, clamped to 0.5–1.5. |
size | number | 0.457 | Orb diameter as a fraction of component width. |
complete | boolean | false | Settles the fluid and reveals the completion mark. |
completeLabel | string | 'All set' | Status shown after completion. |
backgroundColor | string | '#090512' | Component background. |
fontFamily | string | System font | Status-label font family. |
badgeFontFamily | string | System font | Badge font family. |
onCompleteAnimationEnd | () => void | — | Called on the JS thread when completion finishes. |
accessibilityLabel | string | Current visible label | Screen-reader label. |
style | StyleProp<ViewStyle> | — | Outer-container style. |
testID | string | — | Outer-container test identifier. |
Compatibility
- Expo SDK 57
- React Native 0.86
- Reanimated 4.5
- React Native Skia 2.6
- iOS: supported, not yet verified on a device
- Android: supported, not yet verified on a device
- Web: verified
- Works in Expo Go because Skia, Reanimated, and Worklets are included in the SDK
Accessibility
The component exposes a labeled progress bar and reports whether it is busy. With reduced motion enabled, the fluid stays on a fixed frame, the halo stops breathing, and the completion mark fades in instead of drawing along its path.
FAQ
- Does the liquid orb loader work on the web?
- Yes, web is verified, but CanvasKit must be copied into the public directory and loaded before mounting Skia. iOS and Android are supported with device verification pending.
- Can I control when the liquid loader completes?
- Yes. Set the complete prop or call complete through the ref, listen with onCompleteAnimationEnd, and call reset to return to the active loading state.
- What does the loader expose to assistive technology?
- It is a labeled progress bar that reports whether it is busy. Reduce Motion freezes the fluid and halo, then fades in the completion mark instead of drawing it.




