Skip to content
Native Animation
Book Discover Detail animation preview

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

npx nativeanimation add book-discover-detail

Book Discover Detail

A book discovery flow with cover-to-detail transitions and 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 book discovery flow with cover-to-detail transitions and configurable books, labels, colors, and fonts.

How it works

  1. Stories, the reading card, and shelf covers measure their source rectangle on the UI thread. The source hides while one floating cover layer interpolates its position, size, corner radius, crop, and rotation.
  2. One detail shared value drives the flight, expanding hero tint, and Discover fade. A second reveal axis introduces the listening pill, metadata, and drawn checks.
  3. paywall moves a full-height sheet and pushes the detail backward. A two-row cover mosaic travels in opposite directions.
  4. A single plan axis moves one selection frame and rolls the trial line. Separate pressure values keep touches from resetting screen progress.
  5. Back, edge drag, cover drag, and the sheet's top drag area provide dismissal. All animation methods can be called through the ref.

Install

Copy the text files listed in piece.json, then install compatible packages:

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

Mount inside GestureHandlerRootView. For web, initialize CanvasKit before importing the component (the standard Skia web setup). Load fonts once in the host. Icons: Lucide (ISC), license included.

Usage

import { BookDiscoverDetail } from './book-discover-detail';

<BookDiscoverDetail
  books={books}
  storyIds={books.slice(0, 4).map((book) => book.id)}
  continueReading={{ id: books[2].id, progress: 0.42 }}
  shelf={{ title: 'Reading list', subtitle: 'A fresh perspective', ids: books.map((book) => book.id) }}
  plans={plans}
  onContinue={(planId) => startCheckout(planId)}
/>

books contains { id, title, subtitle, author, cover, tint, coverTitleColor, coverSubtitleColor, coverAlignment?, minutes, chapters, insights, learn, about }. cover is an expo-image source. Titles and subtitles are rendered over the artwork; supply art with quiet space at the top. coverAlignment is left or center. Use three short learning points and a two- or three-sentence description.

plans contains { id, title, detail, trialLine, badge? }. The demo's prices are fictional presentation copy. Checkout, restore, legal links, sharing, and persistence belong to the host.

const screen = useRef<BookDiscoverDetailRef>(null);

<BookDiscoverDetail
  ref={screen}
  books={books}
  storyIds={storyIds}
  continueReading={reading}
  shelf={shelf}
  plans={plans}
  palette="night"
  colors={{ accent: '#B95DE8', accent2: '#D98DF6' }}
  fontFamily="Geist_400Regular"
  titleFontFamily="Geist_700Bold"
  monoFontFamily="GeistMono_400Regular"
  bottomInset={insets.bottom}
  onOpenBook={(id) => trackOpen(id)}
/>

screen.current?.openBook('steady-habits');
screen.current?.openPaywall();

Import useRef from React and BookDiscoverDetailRef from this folder. Supply insets with the host's safe-area integration; the included demo uses useSafeAreaInsets().

Props

PropTypeDefaultPurpose
booksDiscoverBook[]RequiredContent, image sources, cover typography, and tint.
storyIdsstring[]RequiredHorizontal stories in display order.
continueReading{ id, progress }RequiredReading card; progress is a fraction.
shelf{ title, subtitle, ids }RequiredHorizontal editorial shelf.
plansDiscoverPlan[]RequiredOrdered subscription options.
initialPlanstringLast planInitial selected ID.
labelsPartial<DiscoverLabels>EnglishAll fixed copy and accessibility labels. Templates use {value} and {title}. headline and tabs are tuples.
colorsPartial<DiscoverColors>Paper tokensBackground, surfaces, text, accents, dividers, chip colors, danger, on-colors, and scrim.
colorSchemelight | dark | autolightSystem appearance selection.
palettepaper | night | Partial<DiscoverColors>paperMeasured cream palette or an original Night interpretation.
fontFamilystringSystemBody typeface.
titleFontFamilystringSystemHeading and cover title typeface; pass a loaded bold face.
monoFontFamilystringSystemCompletion percentage typeface.
motionsystem | reducedsystemAccessibility motion mode.
bottomInsetnumber0Real bottom system inset; zero in an already inset host.
styleStyleProp<ViewStyle>—Root layout override.
testIDstringbook-discover-detailAutomation prefix.
accessibilityLabelstring—Host root description.
onOpenBook, onListen(id) => void—Detail and listening actions.
onCloseBook, onClosePaywall() => void—Dismissal actions.
onSelectPlan, onContinue(id) => void—Plan selection and host checkout.
onTabChange(index) => void—Visual tab changes; Explore content remains in place.
onShareBook(id) => void—Host sharing integration.
onRestorePurchase() => void—Host purchase restoration.
onLegalPress(terms | privacy) => void—Legal-link destination.
onInteraction() => void—Stop an external timeline on contact.
autoplayboolean—Demo contract; timers live in demo/.

Ref methods: openBook(id), closeBook(), openPaywall(), closePaywall(), selectPlan(id). Book IDs should appear in a story, the reading card, or the shelf so there is a measurable source. Save state is local to this screen's lifetime. Content arrays should have stable IDs.

Compatibility

Expo SDK 58, React Native 0.88, Reanimated 4.7, Worklets 0.13, Gesture Handler 3.3, Skia 2.14, expo-image, and expo-linear-gradient. Intended for iOS, Android, and web with the New Architecture. The installed modules are included in the project's Expo Go environment; a custom host must configure Reanimated and Skia normally.

The viewport measures its container, centers at a maximum width of 430 pt, and caps tablet height to the reference phone aspect ratio. Short containers and landscape preserve readable geometry with vertical scrolling. Content scrolls below a fixed tab bar. bottomInset protects its controls and the plan's scroll footer; the host owns the top safe area. Do not add insets twice. The top band is reserved, and important controls avoid the viewer's upper-right 56 pt square. The home indicator is decorative and appears only when no bottom inset is supplied.

The Paper theme follows the cream reference. Night is an original palette translation, not another reference screen; book artwork and per-book hero tints retain their original colors. Cover art in the demo is 768 × 1024, enough for the 172 × 229 pt hero at 3×. Assets are passed by the demo and are not required by the reusable files.

Accessibility

Controls expose labels, roles, selected states, and accessibility activation. Buttons and cover targets are at least 48 pt. Back and Close provide tap alternatives to the pan gestures. Hidden screens are removed from the accessibility tree. Reduced motion replaces screen flights with 220 ms fades, removes pressure scaling, stops the story-ring gradient and mosaic, and displays complete checks. Body text follows system scaling; cover typography is artwork-sized. Informational body text has a platform-aware minimum of 11 pt on iOS and 12 sp on Android.

Why this one

A cover keeps its identity as it moves from a cropped story or shelf into a readable book detail. Its own tint fills the hero, the listening action lands with a small spring, and a single moving plan border makes the next decision easy to follow. The demo uses seven original book records and local artwork rather than network placeholders.