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>
  );
}
PropTypeDefaultDescription
durationnumber300Animation duration in milliseconds
delaynumber0Delay before the animation starts in milliseconds
childrenReactNodeContent 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>
  );
}
PropTypeDefaultDescription
distancenumber50Starting offset in pixels below final position
durationnumber300Animation duration in milliseconds
delaynumber0Delay before the animation starts in milliseconds
childrenReactNodeContent 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>
  );
}
PropTypeDefaultDescription
scalenumber0.95Scale factor when pressed (0–1)
onPress() => voidCalled when the press is released
childrenReactNodeContent 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>
  );
}
PropTypeDefaultDescription
dampingnumber8Spring damping — higher values reduce oscillation
stiffnessnumber200Spring stiffness — higher values produce faster motion
childrenReactNodeContent 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>
  );
}
PropTypeDefaultDescription
intervalnumber100Delay between each child’s animation start in milliseconds
durationnumber300Duration of each child’s fade-in
childrenReactNodeChildren 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>
  );
}
PropTypeDefaultDescription
countnumber60Number of confetti particles
durationnumber2000Total animation duration in milliseconds
colorsstring[]theme accent paletteParticle colours
spreadnumber160Horizontal spread angle in degrees
origin?{ x: number; y: number }top-centerLaunch origin as a fraction of container size (0–1)
loopbooleanfalseRepeat the burst continuously
childrenReactNodeContent 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>
  );
}
PropTypeDefaultDescription
autoShakebooleantrueShake once on mount
distancenumber10Maximum horizontal offset in pixels
cyclesnumber4Number of back-and-forth cycles
durationnumber400Total shake duration in milliseconds
childrenReactNodeContent 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>