Thinking Orb
A dotted thought-orb with nine hand-tuned Skia states and a global Dynamic Island toast for showing what an agent is doing.
Prerequisites
The orb draws on Skia, the Island is Reanimated-driven, and the toggle press gets a haptic.
npx expo install @shopify/react-native-skia expo-haptics expo-status-bar react-native-reanimated react-native-safe-area-context
Install
npx @rslab/cli add orb
Usage
The primary way to use this component is as a global toast: mount DynamicIslandProvider once, beside your root navigator, then call useDynamicIslandToast() from any screen to present, update, or dismiss it.
import { NavigationContainer } from '@react-navigation/native';
import { DynamicIslandProvider } from '@/components/ui/orb';
export default function App() {
return (
<DynamicIslandProvider defaults={{ islandGlow: 0.3, duration: 4_000 }}>
<NavigationContainer>{/* Stack / Tabs */}</NavigationContainer>
</DynamicIslandProvider>
);
}import { useDynamicIslandToast } from '@/components/ui/orb';
export function SearchButton() {
const island = useDynamicIslandToast();
return (
<Button
title="Search"
onPress={() =>
island.show({
state: 'searching',
text: 'Searching your workspace',
orbSpeed: 1.25,
orbGlow: 0.55,
islandGlow: 0.25,
duration: 5_000,
})
}
/>
);
}show(options) presents or replaces the current notification, update(options) changes an open Island without replaying its entrance, and hide() dismisses it. Set duration: 0 to keep it open until hide() is called. By default, pressing the Island dismisses it; set dismissOnPress: false to keep it visible. For Expo Router, wrap the root Stack or Slot in app/_layout.tsx the same way.
The orb itself also works standalone, without the Island, wherever you'd drop any other loading indicator:
import { ThinkingOrb } from '@/components/ui/orb';
<ThinkingOrb state="working" size={64} glow={0.3} />;Props
useDynamicIslandToast()
show(options)?DynamicIslandToastOptions-Presents the Island, replacing any current notification.
update(options)?Partial<DynamicIslandToastOptions>-Patches the open Island in place, no re-entrance.
hide()?() => void-Dismisses the active notification.
visible?boolean-Whether the global Island is currently expanded.
DynamicIslandToastOptions
state?'working''searching''solving''listening''connecting''weaving''composing''breathing''shaping''working'Which of the nine hand-tuned orb animations to play.
text?string-Overrides the per-state default shimmer line, e.g. 'Agent is working'.
orbSpeed?number1Orb animation speed multiplier.
orbGlow?number0.35Soft halo intensity around the orb, from 0 to 1.
islandGlow?number0.35Ambient white glow behind the always-black Island shell, from 0 to 1.
hideStatusBar?booleantrueHides the system status bar while expanded, like a real Island take-over.
duration?number4000Auto-dismiss delay in ms. Use 0 to keep it open until hide() is called.
onPress?() => void-Called when the expanded Island is pressed.
dismissOnPress?booleantrueDismisses the Island after onPress runs.
ThinkingOrb
state?OrbState'working'Which animation to show — see the state list above.
size?642064Tuned size preset. Each size has its own dot count, dot size and speed — not a scale factor.
theme?'auto''dark''light''auto'auto resolves from useColorScheme() and live-updates with it. dark draws light ink for dark backgrounds, light draws dark ink.
speed?number1Speed multiplier on top of the preset's baked speed.
glow?number0Soft halo intensity around the rendered dots, from 0 (off) to 1.
paused?booleanfalseFreezes the animation on the current frame.
aria-label?string-Accessibility label; defaults to a per-state description.
DynamicIsland
The lower-level piece the provider wraps, useful if you want to drive expand/collapse yourself instead of the toast API.
expandedboolean-Drives the open/close animation.
onToggle?() => void-Called on press.
state, text, orbSpeed, orbGlow, islandGlow, hideStatusBar?—-Same as DynamicIslandToastOptions above.
See exactly how this works with an RSLAB subscription.
Get Pro