Animation Primitives
Subpath import
Animations live in a separate subpath because they depend on react-native-reanimated, an optional peer dependency. Never import them from the main barrel.
import {
FadeIn,
SlideUp,
ScalePress,
SpringBounce,
Stagger,
Confetti,
ErrorShake,
} from '@objectifthunes/limestone-sdk/animations';
Install the peer dependency first:
pnpm add react-native-reanimated
Follow the Reanimated installation guide to add the Babel plugin and rebuild native modules.
FadeIn
Opacity 0 → 1 on mount using withTiming.
import { FadeIn } from '@objectifthunes/limestone-sdk/animations';
function WelcomeMessage() {
return (
<FadeIn duration={400} delay={100}>
<Text>Welcome back</Text>
</FadeIn>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
duration | number | 300 | Animation duration in milliseconds |
delay | number | 0 | Delay before the animation starts in milliseconds |
children | ReactNode | — | Content to fade in |
SlideUp
Translates up from distance pixels below the final position while fading in.
import { SlideUp } from '@objectifthunes/limestone-sdk/animations';
function Card() {
return (
<SlideUp distance={30} duration={350} delay={50}>
<View style={styles.card}>
<Text>Card content</Text>
</View>
</SlideUp>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
distance | number | 50 | Starting offset in pixels below final position |
duration | number | 300 | Animation duration in milliseconds |
delay | number | 0 | Delay before the animation starts in milliseconds |
children | ReactNode | — | Content to slide up |
ScalePress
Spring scale on press and release. Wraps Pressable.
import { ScalePress } from '@objectifthunes/limestone-sdk/animations';
function AnimatedButton({ onPress, children }) {
return (
<ScalePress scale={0.93} onPress={onPress}>
<View style={styles.button}>
{children}
</View>
</ScalePress>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
scale | number | 0.95 | Scale factor when pressed (0–1) |
onPress | () => void | — | Called when the press is released |
children | ReactNode | — | Content inside the pressable area |
SpringBounce
Scale 0 → 1 on mount using a spring animation. Good for icons, badges, and modal content.
import { SpringBounce } from '@objectifthunes/limestone-sdk/animations';
function SuccessIcon() {
return (
<SpringBounce damping={10} stiffness={180}>
<Icon name="check-circle" size="xl" color="primary" />
</SpringBounce>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
damping | number | 8 | Spring damping — higher values reduce oscillation |
stiffness | number | 200 | Spring stiffness — higher values produce faster motion |
children | ReactNode | — | Content to bounce in |
Stagger
Wraps each direct child in a FadeIn with a staggered delay. Use it for lists, grids, and menu items.
import { Stagger } from '@objectifthunes/limestone-sdk/animations';
function MenuItems({ items }) {
return (
<Stagger interval={60} duration={250}>
{items.map((item) => (
<MenuItem key={item.id} item={item} />
))}
</Stagger>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
interval | number | 100 | Delay between each child’s animation start in milliseconds |
duration | number | 300 | Duration of each child’s fade-in |
children | ReactNode | — | Children to stagger; each receives an increasing delay |
The first child starts immediately, the second starts after interval ms, the third after interval * 2 ms, and so on.
Composition
Animation components nest freely. Combine them to build layered entrance sequences.
import { FadeIn, SlideUp, Stagger, SpringBounce } from '@objectifthunes/limestone-sdk/animations';
function OnboardingScreen() {
return (
<FadeIn duration={500}>
{/* The whole screen fades in */}
<View style={styles.container}>
{/* Headline slides up with a short delay */}
<SlideUp distance={20} delay={150}>
<Text variant="display">Get started</Text>
</SlideUp>
{/* Feature list staggers in after the headline */}
<Stagger interval={80} duration={300}>
<FeatureRow icon="lock" label="Secure by default" />
<FeatureRow icon="bolt" label="Blazing fast" />
<FeatureRow icon="heart" label="Built with care" />
</Stagger>
{/* CTA button bounces in last */}
<SpringBounce damping={12} stiffness={220}>
<Pressable style={styles.cta}>
<Text>Continue</Text>
</Pressable>
</SpringBounce>
</View>
</FadeIn>
);
}
Confetti
Bursts particle confetti over the wrapped content on mount or on demand. Ideal for celebration moments — completed purchases, finished onboarding, achieved goals.
import { Confetti } from '@objectifthunes/limestone-sdk/animations';
function PurchaseSuccess() {
return (
<Confetti count={80} duration={2500}>
<SuccessBanner />
</Confetti>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
count | number | 60 | Number of confetti particles |
duration | number | 2000 | Total animation duration in milliseconds |
colors | string[] | theme accent palette | Particle colours |
spread | number | 160 | Horizontal spread angle in degrees |
origin? | { x: number; y: number } | top-center | Launch origin as a fraction of container size (0–1) |
loop | boolean | false | Repeat the burst continuously |
children | ReactNode | — | Content rendered below the particle layer |
When useReducedMotion is active, particles are not rendered at all.
ErrorShake
Shakes the wrapped content horizontally to signal an error — like a failed login form or an invalid input. Triggers once on mount; call the imperative shake() handle to re-trigger.
import { ErrorShake } from '@objectifthunes/limestone-sdk/animations';
import { useRef } from 'react';
import type { ErrorShakeRef } from '@objectifthunes/limestone-sdk/animations';
function LoginForm() {
const shakeRef = useRef<ErrorShakeRef>(null);
const handleSubmit = async () => {
const ok = await login(credentials);
if (!ok) shakeRef.current?.shake();
};
return (
<ErrorShake ref={shakeRef} autoShake={false}>
<TextInput value={password} onChangeText={setPassword} secureTextEntry />
</ErrorShake>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
autoShake | boolean | true | Shake once on mount |
distance | number | 10 | Maximum horizontal offset in pixels |
cycles | number | 4 | Number of back-and-forth cycles |
duration | number | 400 | Total shake duration in milliseconds |
children | ReactNode | — | Content to shake |
ErrorShakeRef exposes a single method: shake() => void.
Reduced motion
When the user has enabled the system-level reduced motion preference, all seven components skip their animation and render children at their final state immediately. No conditional rendering or extra props are needed.
// This works correctly for users who prefer reduced motion
// — the content appears instantly without animation
<SlideUp distance={40} duration={400}>
<ImportantContent />
</SlideUp>