Skip to content
Native Animation
Tilted Grid Onboarding animation preview
Onboarding

Tilted Grid Onboarding

React Native Tilted Photo Grid Onboarding

A full-screen onboarding pattern with four tilted photo rows that enter together, then take turns moving through the grid.

$9 for this animation

Checkout opens soon. Leave your email and we will tell you the moment you can buy it.

One email when checkout opens. No spam.

Add to your project

Copy the component and its assets into your app with the Native Animation CLI, or paste the agent prompt into Claude Code, Codex or Cursor once the MCP server is connected.

npx nativeanimation add tilted-grid

About this animation

A React Native animated photo grid can show a broad creative collection before a welcome action. This component arranges 32 images into four tilted rows, duplicates each row for wrapping, and takes turns moving alternating rows in opposite directions. It waits for image loading or a configurable timeout before revealing the composition, while Reanimated runs row travel and staggered text entrances on the UI thread. Use it for a creative-tool introduction, a photo-collection welcome, an inspiration gallery, or an image-led onboarding screen. Supply your own cards and replace heading segments, supporting copy, and action text. Customize card proportions, gaps, corners, grid rotation and scale, colors, fonts, loading timeout, entrance timing, and row-turn rhythm. Connect the primary action and entrance callbacks, or replay through the ref.

When to use it

  • Introduce a creative image collection.
  • Welcome users with a tilted photo wall.
  • Preview an inspiration gallery.
  • Stage an image-led onboarding action.

A full-screen onboarding pattern with four tilted photo rows that enter together, then take turns moving through the grid.

How it works

  1. The component measures its own container with onLayout, so card and grid sizes stay proportional inside a screen, modal, or tablet layout.
  2. It waits for all 32 card images to load, with a configurable timeout as a fallback, before revealing the composition.
  3. Each row renders a second copy of its eight cards so it can wrap without exposing an empty edge.
  4. Reanimated shared values drive the row turns and the staggered copy entrance on the UI thread.
  5. Alternating rows move in opposite directions, with their turns offset so only one row moves at a time.

Install

npx expo install expo-image expo-linear-gradient react-native-reanimated

Usage

import TiltedGridOnboarding from './TiltedGridOnboarding';

const cards = [
  require('./assets/card-01.jpg'),
  // Add 31 more local or remote image sources.
];

export function WelcomeScreen() {
  return <TiltedGridOnboarding cards={cards} />;
}

Customize the measured look and replay the full entrance when needed:

import { useRef } from 'react';
import TiltedGridOnboarding, {
  type TiltedGridOnboardingRef,
} from './TiltedGridOnboarding';

export function WelcomeScreen() {
  const onboardingRef = useRef<TiltedGridOnboardingRef>(null);

  return (
    <TiltedGridOnboarding
      ref={onboardingRef}
      cards={cards}
      title="Make your"
      highlightedTitle="next idea"
      titleSuffix="feel real"
      subtitle="Turn a short prompt into something worth sharing."
      ctaLabel="Start creating"
      accentColor="#7C3AED"
      gridRotation={-8}
      turnDuration={900}
      titleFontFamily="YourRegularFont"
      highlightedTitleFontFamily="YourBoldFont"
      ctaFontFamily="YourSemiboldFont"
      onCtaPress={() => continueOnboarding()}
      onAnimationStart={() => trackAnimationStart()}
    />
  );
}

The forwarded ref exposes replay().

Props

PropTypeDefaultDescription
cardsImageSourcePropType[]RequiredThe 32 images displayed across four rows.
titlestring'Bring your'Copy before the emphasized title text.
highlightedTitlestring'ideas'Emphasized copy on the title's second line.
titleSuffixstring'to life'Copy after the emphasized title text.
subtitlestring'Create something remarkable from a simple prompt.'Supporting copy below the title.
ctaLabelstring'Get started'Primary action label.
ctaAccessibilityLabelstringctaLabelScreen-reader label for the primary action.
onCtaPress() => void—Called when the primary action is pressed.
onAnimationStart() => void—Called whenever an entrance sequence begins.
backgroundColorstring'#0E0A1F'Background behind the grid and content.
accentColorstring'#7C3AED'Primary action color.
cardBackgroundColorstring'#241B46'Placeholder color while card images load.
cardGapnumber8Gap between cards and rows in points.
cardWidthRationumber0.3Card width as a fraction of the component width.
cardHeightRationumber0.95Card height as a fraction of its width.
gridHeightRationumber0.58Grid viewport height as a fraction of the component height.
gridRotationnumber-8Grid rotation in degrees.
gridScalenumber1.15Scale applied to the complete grid.
cardBorderRadiusnumber12Card corner radius in points.
imageLoadTimeoutnumber1500Maximum image-loading wait before the entrance starts, in milliseconds.
loopStartDelaynumber1600Delay before the first row turn begins, in milliseconds.
turnDurationnumber900Duration of each row turn in milliseconds.
turnPausenumber600Pause included between row turns, in milliseconds.
entranceDurationnumber350Duration of the copy and action entrances, in milliseconds.
rowEntranceDurationnumber450Duration of each row entrance, in milliseconds.
firstRowEntranceDelaynumber80Delay before the first row enters, in milliseconds.
rowEntranceStaggernumber140Additional delay for each consecutive row, in milliseconds.
subtitleEntranceDelaynumber80Delay before the subtitle enters, in milliseconds.
ctaEntranceDelaynumber200Delay before the primary action enters, in milliseconds.
ctaEntranceScalenumber0.96Initial scale of the primary action entrance.
ctaPressScalenumber0.96Scale reached halfway through action feedback.
ctaPressDurationnumber120Duration of each half of action feedback, in milliseconds.
entryEasingEasingFunctionEasing.out(Easing.cubic)Easing used by entrances and action feedback.
loopEasingEasingFunctionEasing.bezier(0.65, 0, 0.35, 1)Easing used by row turns.
titleFontFamilystringSystem fontFont for regular title copy.
highlightedTitleFontFamilystringSystem bold fontFont for emphasized title copy.
subtitleFontFamilystringSystem fontFont for supporting copy.
ctaFontFamilystringSystem semibold fontFont for the primary action label.
styleStyleProp<ViewStyle>—Outer-container style.
testIDstring—Test identifier for the outer container.

Compatibility

  • Expo SDK 57
  • React Native 0.86
  • Reanimated 4.5
  • iOS: supported, not yet verified on a device
  • Android: supported, not yet verified on a device
  • Web: verified
  • Works in Expo Go because its native dependencies are included in the SDK

Accessibility

The primary action is exposed as a button and accepts a custom screen-reader label. With reduced motion enabled, the looping card movement stops and the card rows, title, subtitle, and action use a short fade; the button keeps its brief press feedback.

FAQ

How many images does the tilted photo grid use?
The documented cards API uses 32 images across four rows. Each row renders a second copy of its eight cards to wrap without exposing an empty edge.
Can I change the grid proportions and animation rhythm?
Yes. Configure cardWidthRatio, cardHeightRatio, gridHeightRatio, cardGap, gridRotation, gridScale, turnDuration, turnPause, and the entrance timing props.
Does the grid wait for images before animating?
Yes. It waits for all images or imageLoadTimeout, then starts the entrance. Reduce Motion stops looping card travel and replaces the entrances with short fades.