Real Page Flip Engine for Flutter
A production-hardened page flip engine for Flutter. Single-page and double-spread. Physics-based paper fold, adaptive haptics, sound, dark mode. Runs on Android, iOS, Web (CanvasKit + WASM), Windows, macOS, and Linux — all 6 Flutter platforms.
Built for RealBible. Running in Production.
Real Page Flip is the rendering engine behind two live Google Play apps:
This is not a weekend prototype. It is the engine that thousands of readers use every time they turn a page. Every edge case below was encountered on a real device, reported by a real user, and fixed:
| Real-world issue | Resolved |
|---|---|
| iPhone SE haptic motor buzz | Fixed |
| Dark-paper shadow blade artifacts | Fixed |
| Single-page flap splitting into stacked sheets | Fixed |
| Extreme vertical drag causing layer seams | Fixed |
| GPU memory leak from static shader cache | Fixed |
1,199 tests. 0 analyzer issues. Free (MIT) for any project, commercial or personal.
This engine is different because it has already solved edge cases that only surface after thousands of real-world page turns.
English | 한국어
What Sets This Engine Apart
- Real-device verified: Tested on budget iPhone SE and low-end Android devices — every listed bug was reported by an actual user and fixed.
- 1,199 tests, 0 analyzer issues: Covers gesture arbitration, geometry invariants, memory lifecycle, accessibility, and stress scenarios.
- Adaptive performance: Three rendering profiles (low/medium/high) automatically scale to device capability.
- Physics-modeled visuals: Crease shadows, paper curl shading, and dark-paper moonlight tones derived from physical paper behavior.
- Complete sensory feedback: Continuous haptic waveform pipeline synchronized with speed-varying page-rustle audio.
- Production architecture: 31 focused source files with documented structure.
Demos
Live Web Preview
Drag or tap the pages to feel the physics. Switch between single-page and double-spread mode, tune sensitivity and paper opacity, or toggle haptics (on a real device) — all from the in-app control deck.
Mobile single-page view
Four slow page turns on a portrait mobile viewport using the high-quality rendering profile.

16:9 double-spread view
Four slow spread turns with distinct left- and right-page content, on a 16:9 landscape viewport.

Technical Foundation
Hybrid Snapshot Engine
During a flip, the renderer works from flattened page textures instead of repainting the full widget tree every frame. Actual frame rate depends on page capture cost, device, and host layout.
Intelligent Memory Windowing
Retained page state is bounded around the active page window. Whether your book has 10 pages or 10,000, memory footprint stays constant.
Lightweight Geometry Engine
Curved clips, dynamic shadows, and highlights are calculated with a custom math-based Path Clipping engine — no heavy 3D perspective transforms.
Production-Hardened Layouts
Internal constraint gate prevents "unbounded height" errors in common Stack,
Column, and Scaffold compositions.
Sensory Experience
- Sound: High-quality page-rustle audio that varies naturally with gesture speed.
- Haptics: Perceptual gain pipeline with adaptive quality routing. Continuous waveform texture on premium devices, discrete confirmation on basic motors.
Installation
flutter pub add real_page_flip
Quick Start
import 'package:real_page_flip/real_page_flip.dart';
PageFlipWidget(
itemCount: 10,
itemBuilder: (context, index) => MyPage(index),
)
Single-page settle policy
Controls whether the moving back face eases into the destination near the end of a single-page turn. Disable for a stable back face until the page commits:
PageFlipWidget(
config: const PageFlipConfig(
enableSinglePageSettleReveal: false,
),
itemCount: 10,
itemBuilder: (context, index) => MyPage(index),
)
Double-spread mode always maps the physical verso and ignores this setting.
Snapshot refresh and thermal budget
For long, scrollable, or provider-heavy pages, use dirty-aware refreshing:
final flipController = PageFlipController();
PageFlipWidget(
controller: flipController,
contentRevision: documentRevision,
config: const PageFlipConfig(
snapshotRefreshPolicy: PageFlipSnapshotRefreshPolicy.whenDirty,
maxSnapshotPixelRatio: 2.25,
),
itemCount: pages.length,
itemBuilder: (context, index) => pages[index],
)
flipController.markPageDirty(changedPageIndex);
flipController.markCurrentPageDirty(prewarm: false);
whenDirty observes scrolling and pre-captures after scroll end. Use
contentRevision for declarative refresh, or markPageDirty() for one page.
maxSnapshotPixelRatio caps only the moving raster texture; settled content
remains at native resolution.
Flip Sensitivity
Independent forward/backward drag thresholds and gesture sensitivity:
PageFlipWidget(
config: PageFlipConfig(
cutoffForward: 0.35,
cutoffPrevious: 0.5,
sensitivity: 0.5,
),
itemCount: 10,
itemBuilder: (context, index) => MyPage(index),
)
Double-spread (two-page) mode
PageFlipWidget(
spreadMode: PageFlipSpreadMode.doubleSpread,
itemCount: spreadCount,
config: PageFlipConfig(
flapBackStrength: 0.0, // mirrored back text disabled by default
),
itemBuilder: (context, spreadIndex) => MyTwoPageSpread(spreadIndex),
)
| Responsibility | Detail |
|---|---|
itemBuilder |
Each index renders a full-width spread (left + right pages). |
itemCount |
Number of spreads (e.g. ceil(pageCount / 2)). |
| Spine reveal | Forward reveals the left half of the next spread; backward the right half of the previous. |
Dark Mode
Theme-aware by default. Shadows, highlights, and edge masks adapt automatically based on background luminance. Zero config:
MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.system,
home: Scaffold(
body: PageFlipWidget(
itemCount: pages.length,
itemBuilder: (context, index) => MyPage(index),
),
),
)
Performance Benchmark
cd example
flutter run --profile -t lib/performance_benchmark.dart \
--dart-define=PERFORMANCE_PROFILE=medium \
--dart-define=FLIPS=80
The benchmark runs 80 consecutive page flips on a real device and reports:
| Metric | Target |
|---|---|
| Build time (avg) | < 6 ms |
| Raster time (avg) | < 5 ms |
| P90 frame time | < 10 ms |
| P99 frame time | < 12 ms |
| Max frame time | < 18 ms |
| Jank count (80 flips) | 0 |
Run across low/medium/high profiles to validate your target device tier. The benchmark is designed to catch regressions in snapshot capture, geometry computation, and shader performance before they reach users.
Support the Project
Real Page Flip is free (MIT) and always will be. Maintaining a production-grade engine — running 1,199 tests, verifying fixes across real devices, and keeping pace with Flutter releases — requires sustained investment.
For companies, sponsorship tiers include having your name or logo listed here.
License
MIT — free for any project, commercial or personal. See LICENSE.
Built by ChaPDCha