Skip to content

Repository files navigation

Natural Page Turn for React Native

Verify npm License: MIT

A natural-feeling, paper-like page-turn animation for React Native. It combines continuous page geometry, gesture-aware motion, settling and reversion, and Skia rendering instead of playing a canned transition. Image galleries, rasterized PDF pages, and document readers can share the same animation path.

A natural page turn running in a real reader on iPad

Real integration footage from the Persimmon reader on iPad.

Alpha: the package boundary, clean-consumer install, and complete example are validated on the compatibility matrix below. Expect small API changes before 1.0.

Why it feels natural

  • The page bends as a continuous rolled strip rather than a flat card or a corner-only warp.
  • Drag distance, direction, velocity, and release intent feed the same motion model used by automatic turns.
  • A page can commit or settle back naturally instead of snapping at one fixed threshold.
  • Perspective, front/back textures, paper color, and dynamic shadows preserve the visual cues of a turning sheet.
  • natural is the baseline preset; paper weight, curl relaxation, velocity, timing, and commit behavior remain tunable when a product needs a different material feel.

“Natural” is the design goal, not a claim of laboratory-grade paper simulation.

Install

Install the renderer and its native peer dependencies:

pnpm add @chihumyum/react-native-natural-page-turn
npx expo install @shopify/react-native-skia react-native-gesture-handler react-native-reanimated react-native-worklets

Wrap the application root with GestureHandlerRootView. Expo projects include the Worklets transform; React Native Community CLI projects must add react-native-worklets/plugin last in babel.config.js. Rebuild the native app after installing the peer dependencies.

Ten-minute start

PageTurnPager loads adjacent pages, caches them, commits page indices, and supports both direct gestures and imperative playback:

import {
  PageTurnPager,
  imagePageSource,
  type PageTurnPagerHandle,
} from "@chihumyum/react-native-natural-page-turn";
import { useImage } from "@shopify/react-native-skia";
import { useMemo, useRef } from "react";

const first = useImage(require("./assets/first.png"));
const second = useImage(require("./assets/second.png"));
const pager = useRef<PageTurnPagerHandle>(null);
const source = useMemo(
  () => (first && second ? imagePageSource([first, second]) : undefined),
  [first, second],
);

if (!source) return null;

<PageTurnPager
  ref={pager}
  source={source}
  style={{ flex: 1 }}
  preset="natural"
  onPageChange={(pageIndex) => console.log(pageIndex)}
/>;

pager.current?.next();
pager.current?.previous();

Use width and height for a fixed canvas, or give the pager a measurable style. gestureDirection selects which direction a drag claims; the imperative handle can play either direction.

Async content and PDF pages

Use lazyImagePageSource() when pages are decoded on demand:

const source = lazyImagePageSource({
  pageCount: document.pageCount,
  async loadPage(index, size, signal) {
    return renderDocumentPageToSkImage(document, index, size, signal);
  },
  releasePage(_index, image) {
    image.dispose();
  },
});

The library deliberately does not parse PDF or EPUB. Rasterize a requested page to SkImage in the adapter and keep parsing, pagination, and network work out of the gesture hot path. See content adapters.

API layers

  • Package root: PageTurnPager, low-level PageTurn, image page sources, presets, and stable public types.
  • @chihumyum/react-native-natural-page-turn/advanced: mesh, shaders, native-frame helpers, tuning ranges, and renderer internals for custom integrations.
  • @chihumyum/react-native-natural-page-turn/core: platform-neutral solver, gesture state, timing, reversion, and worklet implementation.

Most applications should install only the renderer package. Its dependency on @chihumyum/page-turn-core is resolved automatically.

Presets and tuning

Start with natural, light, heavy, or snappy, then override only the values the product needs:

<PageTurnPager
  preset="heavy"
  tuning={{ gestureCommitThreshold: 0.82 }}
  source={source}
/>

See the tuning guide before exposing raw values in a product UI.

Compatibility

The initial validated matrix is intentionally narrow:

Dependency Validated version
React Native 0.86.2
React 19.2.3
React Native Skia 2.6.2
Reanimated 4.5.1
Worklets 0.10.3
Gesture Handler 2.32.0

The package uses only public APIs from these projects. Wider peer ranges are accepted but should be treated as unverified until added to the consumer test matrix.

Examples and development

Run the image-based Expo example:

pnpm install
pnpm --filter @page-turn-example/basic start

The repository also includes a self-contained PDF and EPUB document demo. Its bundled fixtures work out of the box, and its adapters show the complete path from a document page to SkImage and then to PageTurnPager:

pnpm install
pnpm --filter @page-turn-example/documents prebuild
pnpm --filter @page-turn-example/documents ios
# or
pnpm --filter @page-turn-example/documents android

Because the PDF adapter contains native PDFKit/PdfRenderer code, use a local development build rather than Expo Go. To test your own files, run seed:pdf or seed:epub as described in the document demo README.

Run all source, build-output, archive, and clean-consumer checks:

pnpm check

The pack check builds both packages, confirms workspace dependencies were converted to registry versions, installs the tarballs into a clean temporary consumer, and type-checks the root and advanced entry points.

For setup failures, see troubleshooting.

License

MIT

About

A natural-feeling, paper-like page-turn animation for React Native, powered by Skia.

Topics

Resources

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages