npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-native-swipe-predictor

v0.20.1

Published

Create impossibly responsive swipe interactions by predicting where gestures will end

Readme

React Native Swipe Predictor

Create impossibly responsive swipe interactions by predicting where gestures will end

npm version Platform License

What is this?

React Native Swipe Predictor is a high-performance native module that uses physics-based prediction to determine where touch gestures will end. By starting animations before the user lifts their finger, it creates an incredibly responsive feeling that makes React Native apps feel as smooth as native iOS/Android apps.

The Problem

Normal flow: [Touch] → [Move] → [Lift finger] → [Animation starts] (80ms delay)

Our Solution

With predictor: [Touch] → [Move + Animation starts] → [Done] (0ms delay)

Demo

Swipe Predictor Demo

Left: Standard React Native | Right: With Swipe Predictor

Who Needs This Library?

✅ You NEED this if you're building:

  • Dating apps with card swiping (Tinder-style) - Predict swipe decisions and start card animations early
  • Media apps with heavy images/videos - Pre-load next content based on swipe trajectory
  • Games or drawing apps in React Native - Eliminate input lag for better responsiveness
  • Apps targeting older Android devices (pre-2020) - Compensate for slower touch processing
  • Any UI where 80ms latency is noticeable - Navigation drawers, carousels, dismissible cards

❌ You DON'T need this for:

  • Simple CRUD apps with basic navigation
  • Apps with standard scrolling lists (ScrollView/FlatList handle this well)
  • Apps only targeting iPhone 12+ (already have excellent touch latency)
  • Forms, buttons, or tap-based interactions
  • Apps where animations can wait until after touch release

Real-world impact:

  • Instagram Stories: Pre-load next story when user starts swiping = instant transitions
  • Image Galleries: Start loading hi-res image before swipe completes = no loading state
  • Navigation Drawers: Begin open/close animation during swipe = feels native
  • Card Games: Predict throw trajectory for realistic physics = better game feel

🚀 5-Minute Setup Guide

This library uses Rust for high-performance calculations, but don't worry! Everything is pre-built and you don't need to know Rust or have any Rust tools installed.

Prerequisites

Step 1: Install the Package

# Using npm
npm install react-native-swipe-predictor react-native-gesture-handler react-native-reanimated

# Using yarn
yarn add react-native-swipe-predictor react-native-gesture-handler react-native-reanimated

Step 2: Platform-Specific Setup

iOS Setup

  1. Install CocoaPods dependencies:
cd ios && pod install
  1. Important for M1/M2 Macs: If you encounter architecture issues, try:
cd ios && arch -x86_64 pod install
  1. Open your project in Xcode and ensure:
    • Minimum iOS Deployment Target is 15.1 or higher
    • Build Settings → Enable Bitcode is set to "No"

Android Setup

  1. Ensure your android/build.gradle has:
buildscript {
    ext {
        minSdkVersion = 23  // or higher
        compileSdkVersion = 33  // or higher
        targetSdkVersion = 33  // or higher
    }
}
  1. If you're using React Native 0.73+, no additional setup is needed!

  2. For older React Native versions, add to android/app/build.gradle:

android {
    packagingOptions {
        pickFirst '**/libc++_shared.so'
        pickFirst '**/libjsi.so'
        pickFirst '**/libreact_nativemodule_core.so'
    }
}

Step 3: Verify Installation (optional)

Create a test component to verify everything is working:

import React from "react";
import { View, Text, StyleSheet } from "react-native";
import { useSwipePredictor } from "react-native-swipe-predictor";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
  runOnJS,
} from "react-native-reanimated";

function TestSwipe() {
  const translateX = useSharedValue(0);

  const { onTouchStart, onTouchMove, onTouchEnd } = useSwipePredictor({
    onPrediction: ({ x, confidence }) => {
      "worklet";
      if (confidence > 0.7) {
        console.log("Prediction working! X:", x);
        translateX.value = withSpring(x);
      }
    },
  });

  const gesture = Gesture.Pan()
    .onBegin(() => runOnJS(onTouchStart)())
    .onUpdate((e) => {
      translateX.value = e.translationX;
      runOnJS(onTouchMove)(e);
    })
    .onEnd(() => {
      runOnJS(onTouchEnd)();
      translateX.value = withSpring(0);
    });

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: translateX.value }],
  }));

  return (
    <View style={styles.container}>
      <GestureDetector gesture={gesture}>
        <Animated.View style={[styles.box, animatedStyle]}>
          <Text style={styles.text}>Swipe Me!</Text>
        </Animated.View>
      </GestureDetector>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
  box: {
    width: 200,
    height: 200,
    backgroundColor: "#3498db",
    borderRadius: 20,
    justifyContent: "center",
    alignItems: "center",
  },
  text: {
    color: "white",
    fontSize: 18,
    fontWeight: "bold",
  },
});

export default TestSwipe;

Step 4: Run Your App

# iOS
npx react-native run-ios

# Android
npx react-native run-android

If everything is set up correctly, you should be able to swipe the blue box and see it animate smoothly!

Alternatively, try our Example App.

API Reference

useSwipePredictor(options)

The main hook for gesture prediction.

Options

| Option | Type | Default | Description | | --------------------- | ------------------------------------- | ---------------- | ------------------------------------------------------------ | | confidenceThreshold | number | 0.7 | Minimum confidence (0-1) required to trigger predictions | | updateInterval | number | 16 | How often to emit predictions in milliseconds (16ms = 60fps) | | onPrediction | function | - | Called with prediction data when confidence threshold is met | | physics | 'ios' \| 'android' \| PhysicsConfig | Platform default | Physics model to use for predictions | | debug | boolean | false | Show debug overlay with prediction visualization |

Returns

| Property | Type | Description | | -------------- | -------------------- | -------------------------------------------- | | onTouchStart | () => void | Call when gesture begins | | onTouchMove | (event) => void | Call on gesture update with event data | | onTouchEnd | () => void | Call when gesture ends | | prediction | Prediction \| null | Current prediction data | | isActive | boolean | Whether a gesture is currently being tracked |

Prediction Object

interface Prediction {
  x: number; // Predicted end X position
  y: number; // Predicted end Y position
  vx: number; // Current X velocity
  vy: number; // Current Y velocity
  confidence: number; // Prediction confidence (0-1)
  duration: number; // Predicted gesture duration (ms)
}

SwipePredictorDebugOverlay

Visual debugging component that shows prediction data.

import { SwipePredictorDebugOverlay } from "react-native-swipe-predictor";

<SwipePredictorDebugOverlay
  isActive={isActive}
  prediction={prediction}
  touchPoints={touchPoints}
  currentVelocity={velocity}
/>;

Performance

Our Rust-powered prediction engine delivers:

  • < 0.5ms prediction calculation time
  • 60-120 FPS support with no frame drops
  • < 1MB memory footprint
  • 0% CPU usage when idle

Benchmark Results

Device: iPhone 15 Pro (120Hz)
Average Latency: 0.42ms
Max Latency: 1.2ms
Maintained FPS: 120
1000 swipes: 0 dropped frames

Advanced Usage

Helper Hooks

We provide pre-built hooks for common use cases:

usePredictiveImageGallery

Optimized for image galleries with smart preloading:

import { usePredictiveImageGallery } from "react-native-swipe-predictor";

const { onTouchMove, onTouchStart, onTouchEnd } = usePredictiveImageGallery({
  images: imageUrls,
  currentIndex,
  imageWidth: SCREEN_WIDTH,
  onPreload: (indices, priority) => {
    indices.forEach((index) => {
      Image.prefetch(imageUrls[index]);
    });
  },
  preloadRadius: 2, // Preload 2 images in each direction
});

usePredictiveCards

Perfect for Tinder-style card interactions:

import { usePredictiveCards } from "react-native-swipe-predictor";

const { onTouchMove, onTouchStart, onTouchEnd, predictedAction } =
  usePredictiveCards({
    onActionPredicted: (action, confidence) => {
      "worklet";
      switch (action) {
        case "like":
          cardRotation.value = withSpring(15);
          break;
        case "dislike":
          cardRotation.value = withSpring(-15);
          break;
        case "superlike":
          cardScale.value = withSpring(1.2);
          break;
      }
    },
    horizontalThreshold: 120,
    verticalThreshold: -100,
  });

usePredictiveNavigation

For navigation gestures with directional prediction:

import { usePredictiveNavigation } from "react-native-swipe-predictor";

const { onTouchMove, onTouchStart, onTouchEnd } = usePredictiveNavigation({
  onNavigationPredicted: (direction, confidence) => {
    if (confidence > 0.8) {
      switch (direction) {
        case "left":
          prefetchScreen("NextScreen");
          break;
        case "right":
          prepareGoBack();
          break;
      }
    }
  },
  navigationThreshold: 100,
});

useSwipePredictorWithMetrics

Monitor performance and accuracy:

import { useSwipePredictorWithMetrics } from "react-native-swipe-predictor";

const { onTouchMove, onTouchStart, onTouchEnd, metrics } =
  useSwipePredictorWithMetrics({
    onPrediction: ({ x, y }) => {
      // Your prediction handler
    },
    onValidatePrediction: (prediction, actual) => {
      const distance = Math.sqrt(
        Math.pow(prediction.x - actual.x, 2) +
          Math.pow(prediction.y - actual.y, 2)
      );
      return distance < 50; // Within 50 pixels
    },
  });

console.log("Average confidence:", metrics.averageConfidence);
console.log("Predictions/sec:", metrics.predictionsPerSecond);
console.log("Accuracy:", metrics.accuracy);

Custom Physics

Fine-tune the physics model for your specific use case:

const { onTouchStart, onTouchMove, onTouchEnd } = useSwipePredictor({
  physics: {
    decelerationRate: 1500, // px/s²
    minVelocityThreshold: 50, // px/s
    minGestureTimeMs: 30, // ms
    velocitySmoothingFactor: 0.7,
  },
});

Platform-Specific Behavior

const { onTouchStart, onTouchMove, onTouchEnd } = useSwipePredictor({
  physics: Platform.OS === "ios" ? "ios" : "android",
  // iOS: Smoother, more elastic feel
  // Android: Snappier, more direct response
});

Debug Mode

Enable visual debugging to see predictions in real-time:

const swipePredictor = useSwipePredictor({
  debug: true, // Shows velocity vectors and predicted endpoints
  onPrediction: ({ x, y, confidence }) => {
    console.log(`Prediction: ${x}, ${y} (confidence: ${confidence})`);
  },
});

🔧 Troubleshooting

Common Setup Issues

iOS Build Errors

"Module 'SwipePredictor' not found"

# Solution 1: Clean and reinstall
cd ios
pod deintegrate
pod install

# Solution 2: Clear caches
cd ..
rm -rf ~/Library/Developer/Xcode/DerivedData
npx react-native clean

"Undefined symbols for architecture arm64"

  • This means the Rust library wasn't linked properly
  • Ensure you ran pod install after installing the package
  • Check that your Podfile doesn't exclude arm64 architectures

Build fails on M1/M2 Mac

# Install pods with Rosetta
cd ios
sudo arch -x86_64 gem install ffi
arch -x86_64 pod install

Android Build Errors

"libreact-native-swipe-predictor.so not found"

  • Clean and rebuild:
cd android
./gradlew clean
cd ..
npx react-native run-android

"Duplicate libc++_shared.so" errors

  • Add to android/app/build.gradle:
android {
    packagingOptions {
        pickFirst '**/libc++_shared.so'
        pickFirst '**/libjsi.so'
    }
}

Minimum SDK version errors

  • Update android/build.gradle:
minSdkVersion = 23  // Must be 23 or higher

Runtime Issues

"Cannot read property 'createPredictor' of undefined"

  • The native module didn't link properly
  • For React Native 0.60+: Run npx react-native unlink react-native-swipe-predictor then reinstall
  • For older versions: Manually link following the manual linking guide

App crashes on launch

  • Ensure you've installed required peer dependencies:
npm list react-native-gesture-handler react-native-reanimated

Predictions seem delayed

  • Ensure you're using worklets for onPrediction
  • Check that frame rate isn't being limited by other operations
  • Try reducing updateInterval to 8ms for 120Hz displays

Confidence is always low

  • User might be making erratic movements
  • Try adjusting the physics parameters
  • Ensure touch events are being forwarded correctly

Still Having Issues?

  1. Check our GitHub Issues - Someone might have already solved your problem
  2. Enable debug mode to see what's happening:
const swipePredictor = useSwipePredictor({
  debug: true,
  onPrediction: (prediction) => {
    console.log("Prediction:", prediction);
  },
});
  1. Create a minimal reproduction - This helps identify if the issue is with the library or your setup
  2. Open an issue with:
    • Your React Native version
    • Platform (iOS/Android)
    • Complete error message
    • Minimal code to reproduce

Architecture

React Native Swipe Predictor uses a three-layer architecture:

  1. Rust Core - High-performance physics calculations
  2. Native Bridges - Swift (iOS) and Kotlin (Android) modules
  3. JavaScript API - React hooks and components

The Rust core maintains a rolling buffer of touch points and uses physics equations to predict the final position based on velocity and deceleration patterns.

Comparison

| Feature | Standard RN | With Swipe Predictor | | ------------------ | ----------- | -------------------- | | Response time | 80-120ms | 0ms | | Feels native | No | Yes | | Frame drops | Common | None | | Setup complexity | Low | Low | | Bundle size impact | 0KB | ~200KB |

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

# Remember, this library is made mostly in rust. This setup assumes you already have rust installed
# Clone the repo
git clone https://github.com/emuchnick/react-native-swipe-predictor

# Install dependencies
yarn install

# Build Rust libraries
yarn build:rust

# Run example app
cd example && yarn ios

License

MIT © Ethan Muchnick