Skip to content
Native Animation
Floating Book Hero animation preview

This preview uses fictional demo content. See the props below for the customization options available in this component.

npx nativeanimation add floating-book-hero

Floating Book Hero

A floating book hero that unfolds into a library grid, with configurable books, labels, colors, and fonts.

$9 for this animation

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.

About this animation

A floating book hero that unfolds into a library grid, with configurable books, labels, colors, and fonts.

How it works

  1. Five individually projected faces form the hardcover: front, back, spine, fore-edge, and bottom page edge. A column-major rotation matrix positions every face with perspective, including on native renderers that flatten nested transforms.
  2. A vector shared value controls finger tilt. Release uses a spring with damping 12, stiffness 120, and mass 1. Fast horizontal swipes select the neighboring book.
  3. A separate sheet shared value drives the exact same cover from its Home rectangle to its library rectangle, reducing thickness and rotation as the sheet rises. Other covers enter with a diagonal stagger.
  4. Book changes reveal the back before committing the new cover; metadata rolls into place, and the percentage counts toward its next value. Each cover receives its own image, lettering, binding color, and optional edition seal.
  5. Favorites have their own pressure/pop value and five short-lived heart particles. Continue Reading has independent pressure feedback. The demo host stops its timed sequence on user interaction.

Install

npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler expo-image expo-linear-gradient @shopify/react-native-skia

Copy this folder without demo/. Place your screen beneath GestureHandlerRootView. For web, load Skia's LoadSkiaWeb before dynamically importing this component, and serve canvaskit.wasm from your public directory. Load your fonts in the host before mounting the component. Images enter through props; the component contains no demo assets or catalog imports.

Usage

import { useRef } from 'react';
import FloatingBookHero, {
  type FloatingBook,
  type FloatingBookHeroHandle,
} from './floating-book-hero';

const books: FloatingBook[] = [{
  id: 'field-notes', title: 'Field Notes', author: 'A. Reader',
  published: 'Published May 6th, 2024',
  cover: require('./assets/field-notes.jpg'), coverTitleColor: '#FFFFFF',
  progress: 62, pagesBookmarked: 148, spineColor: '#174954', tint: '#86BBC1',
}];

export function ReadingScreen() {
  const ref = useRef<FloatingBookHeroHandle>(null);
  return <FloatingBookHero ref={ref} books={books} greeting="Hello, Alex"
    user={{ initials: 'AR' }} onContinue={(id) => openReader(id)} />;
}

openReader is your application's navigation callback. The component does not own routing.

<FloatingBookHero
  books={books}
  initialBook={0}
  initialSheet={1}
  colorScheme="dark"
  colors={{ accent: '#68A7EB', accentText: '#12202F' }}
  floatAmplitude={4}
  tiltLimit={28}
  labels={{ library: 'My books', bookmarked: (n) => `${n} saved pages` }}
  onBookChange={(id) => saveCurrentBook(id)}
  onSheetChange={(open) => trackLibrary(open)}
/>

The imperative handle exposes setBook(index), openLibrary(), closeLibrary(), spin(), toggleLike(), and tilt(x, y). Selecting a library cell closes the sheet and flies that book back into the hero. Indices outside the array are clamped; nonfinite indices are ignored.

Props

PropTypeDefaultPurpose
booksreadonly FloatingBook[]RequiredCover sources, title, author, publication line, progress, bookmarked pages, binding, tint, optional favorite and edition seal.
greeting / userstring / { initials: string }Hello / ABHeading and avatar content.
labelsPartial<FloatingBookLabels>English copyAll interface labels, accessibility descriptions, author and page formatters.
colorsPartial<FloatingBookColors>Measured light paletteSurface, ink, muted ink, accent, page material, seal, avatar, progress, and illustration colors.
colorScheme'light' | 'dark' | 'auto''light'Full light/dark palette or system preference.
fontFamilystringSystemInterface text font.
titleFontFamilystringInterface fontHeading, cover, and button font. Individual books may override their cover font, tracking, alignment, and the Home heading line breaks with displayTitle.
monoFontFamilystringHeading fontChanging tabular percentage.
initialBook / initialSheetnumber0 / 0Initial selection and sheet progress.
motion'auto' | 'reduced''auto'Operating-system motion preference or forced reduced mode.
floatAmplitude / tiltLimitnumber6 / 35Ambient travel in points and horizontal finger rotation in degrees.
bottomInsetnumber0Host-provided bottom safe area for the decorative home indicator.
style / testIDStyleProp<ViewStyle> / string— / 'floating-book-hero'Root styling and stable identifier prefix.
accessibilityLabelstring'Reading library'Root description.
onContinue(id: string) => void—Open your reader.
onToggleLike(id: string, liked: boolean) => void—Persist a favorite change.
onBookChange(id: string) => void—Persist selection.
onSheetChange(open: boolean) => void—Observe the requested sheet destination.
onInteraction() => void—Stop a demo host's autoplay on input.

The intended library is a curated four-book selection. Additional rows may extend beyond the bounded viewport; use a dedicated library route for a longer catalog. Initial props are read at mount; replace the component's key when replacing its dataset. All book IDs must be unique. progress is expressed as a percentage, not a fraction.

Compatibility

Expo SDK 58, React Native 0.88, React 19, Reanimated 4.7, Worklets 0.13, Gesture Handler 3.3, and Skia 2.14. Designed for iOS, Android, and web with Expo Go's bundled modules. No new native module or development build is required for this dependency set. The root fills its host, centers at a maximum width of 430 points, and uses a compact composition below 650 points in height. The host owns safe-area padding and passes its real bottom inset. The demo supplies useSafeAreaInsets().bottom.

Accessibility

Buttons expose roles, favorite and selection states, and customizable labels. The library can be opened with a tap or the menu; tapping a cover selects it, so changing books does not require a swipe. Screen-reader activation uses the same controller. The operating-system reduced-motion setting disables floating, specular movement, flip turns, particles, and the favorite bounce; finger tilt is restricted. Percentages use tabular figures, and supporting text stays at least 12 points. Text scaling remains enabled. Cover titles are decorative repetitions of the book's accessible name. At very large system text sizes, let the host provide a taller reading surface.

Why this one

A hardcover feels like an object before becoming a library card: the very same projected cover changes position, thickness, and curvature on an interruptible sheet axis. The reference's quiet hierarchy stays intact while the interaction adds a tangible binding, responsive light, and a return flight into reading.

Icons: Lucide (ISC). Demo cover illustrations are project-owned generated assets. Demo fonts are supplied by the host and are not bundled with the reusable component.