About this animation
A React Native orbiting avatars animation can introduce a social experience through people and objects arranged around a central sparkle. This welcome screen measures its container, positions images on two opposing paths, and keeps them upright while transparent objects add a small independent tilt. One Reanimated frame clock drives both orbital directions, with the outer ring moving more slowly. Skia draws the soft rings, pulsing sparkle, and centered title with a gradient-highlighted second line. Use it for a community welcome, event-planning onboarding, a sharing tool introduction, or a people-focused signup entry. Supply avatar and object images for both rings, customize heading, accent gradients, background, action label, orbit period, and fonts, then connect the action callback. The ref replays the entrance without restarting the orbit clock.
When to use it
- Introduce a community or social tool.
- Welcome users to event planning.
- Arrange people and objects in orbit.
- Create a sharing-focused onboarding screen.
A bright onboarding screen where avatars and dimensional objects circle a softly pulsing sparkle above a gradient-highlighted headline.
How it works
- The component measures its own container with
onLayout; every radius, image size, text size, and content position scales from that local width and height. - One Reanimated frame clock drives both icon paths. The middle ring advances clockwise while the outer ring uses the same time value in reverse at two-thirds of the speed, and each icon remains upright because only its position changes.
- Each icon adds a small sine-wave float. Transparent objects also tilt independently, while avatars stay level inside circular colored halos.
- Skia draws the three soft white rings, the four-point gradient sparkle, and both precisely centered title lines. The sparkle uses two repeating eased animations for its scale and rotation.
replay()restarts the ring reveal, staggered icon springs, and rising content entrance without resetting the continuous orbit clock.
Install
npx expo install expo-image expo-linear-gradient react-native-reanimated @shopify/react-native-skiaOn web, CanvasKit must finish loading before this component mounts. Copy canvaskit.wasm to your public assets and call LoadSkiaWeb from the web entry point:
import { LoadSkiaWeb } from '@shopify/react-native-skia/lib/module/web';
await LoadSkiaWeb({ locateFile: () => '/canvaskit.wasm' });Usage
import OrbitWelcome from './OrbitWelcome';
export function WelcomeScreen() {
return (
<OrbitWelcome
innerItems={[
{
kind: 'avatar',
source: require('./assets/person.jpg'),
ringColor: '#DDEBFF',
},
{ kind: 'object', source: require('./assets/calendar.png') },
{ kind: 'object', source: require('./assets/globe.png') },
{ kind: 'object', source: require('./assets/ticket.png') },
]}
outerItems={[
{ kind: 'object', source: require('./assets/pin.png') },
{
kind: 'avatar',
source: require('./assets/friend.jpg'),
ringColor: '#F1E3FF',
},
{ kind: 'object', source: require('./assets/popper.png') },
]}
/>
);
}Use the visual knobs and imperative control to adapt the pattern:
import { useRef } from 'react';
import OrbitWelcome, { type OrbitWelcomeRef } from './OrbitWelcome';
export function WelcomeScreen() {
const welcomeRef = useRef<OrbitWelcomeRef>(null);
return (
<OrbitWelcome
ref={welcomeRef}
innerItems={innerItems}
outerItems={outerItems}
brand={<YourBrand />}
title="Plan something"
highlight="Worth sharing"
highlightColors={['#3E7BFA', '#C33FF1', '#FF923D']}
sparkleColors={['#D842A0', '#FFAA42']}
backgroundColors={['#DDECF4', '#FCF8FA', '#FAE8EF']}
ctaLabel="Continue"
orbitSeconds={72}
fontFamily="YourSansFont"
titleFont={require('./assets/YourTitleFont.ttf')}
onCtaPress={() => navigateNext()}
/>
);
}The forwarded ref exposes replay().
Props
| Prop | Type | Default | Description |
|---|---|---|---|
innerItems | OrbitItem[] | Required | Items on the middle ring (recommended: 4–7). |
outerItems | OrbitItem[] | Required | Items on the outer ring (recommended: 3–5). |
brand | ReactNode | — | Small mark above the title; hidden when omitted. |
title | string | 'Every gathering' | First title line. |
highlight | string | 'Starts here' | Gradient second title line. |
highlightColors | string[] | Blue, purple, pink, orange | Horizontal gradient colors for the highlighted line. |
sparkleColors | [string, string] | Pink, orange | Top and bottom colors of the central sparkle. |
ctaLabel | string | 'Get started' | Primary action label. |
onCtaPress | () => void | — | Called when the primary action is pressed. |
orbitSeconds | number | 60 | Seconds per middle-ring revolution; the outer ring is 1.5× slower. |
backgroundColors | [string, string, string] | Pale blue, white, pale pink | Left, center, and right background colors. |
fontFamily | string | System font | Font family for the primary action. |
titleFont | DataSourceParam | System font | Skia font source for both title lines. |
style | StyleProp<ViewStyle> | — | Outer-container style. |
testID | string | — | Test identifier for the outer container. |
OrbitItem is either an avatar with source and ringColor, or a transparent object image with source.
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 all native dependencies are included in the SDK
Accessibility
The orbit images are decorative and hidden from screen readers. The two visual title lines are exposed as one combined accessibility label, and the primary action is a labeled button. With reduced motion enabled, the orbits, floating, object tilt, and sparkle pulse stop; the entrance becomes a 200 ms fade.
FAQ
- Can I use my own avatars and transparent object images?
- Yes. Supply innerItems and outerItems. Avatar entries contain source and ringColor; object entries contain a transparent image source.
- Can I change the orbit speed and welcome typography?
- Yes. orbitSeconds sets the middle-ring period and the outer ring takes 1.5 times as long. Configure title, highlight, titleFont, fontFamily, and the gradient palettes.
- Are the orbiting images accessible with Reduce Motion?
- The images are decorative and hidden from screen readers; the title is exposed as one label. Reduce Motion stops orbits, floating, tilt, and sparkle pulse and uses a 200 ms entrance fade.




