# Infinite Loophole: React Native device-motion parallax card stack
> Infinite Loophole is a React Native and Expo component that turns the phone's
> own tilt into depth: an expo-sensors DeviceMotion stream feeds two Reanimated
> shared values, and 11 nested dotted card frames interpolate off them in
> opposing directions, opening a tunnel that recedes into the screen. Free to
> download on Motionary as editable TypeScript source.
Product page: https://motionary.dev/animations/infinite-loophole
Price: Free (as of 2026-09-01, live price on the product page)
License: single developer, unlimited personal and commercial apps
Delivery: instant download of the full TypeScript source
Stack: reanimated, expo, react native gesture handler, react native
Rarity: common
Sold by: Motionary (https://motionary.dev)
## What it is
Infinite Loophole is a React Native parallax card stack driven by the device's
motion sensors rather than by touch. Eleven square card layers sit centred on
top of each other, and the ten behind the front layer are outlined by small
white dots stamped along their four edges, each one smaller and fainter than the
one in front of it. Tilt the phone and every layer slides, but by a different
amount: the frontmost layer stays planted while deeper layers travel further, so
the stack pulls apart into a receding tunnel and closes back up as the phone
returns to level. There is no gesture and nothing to tap in Infinite Loophole;
the interaction is the physical act of moving the handset, which is why it reads
as real depth instead of a flat translation. The Motionary demo puts the stack
on a black stage under a display headline reading "Wanna Jump in?".
## What it does
- Reads the live `DeviceMotion` stream from `expo-sensors` at a 16 ms update
interval (roughly 60 samples per second).
- Maps `rotation.gamma` (roll) to horizontal travel and `rotation.beta` (pitch)
to vertical travel, so both tilt axes are live at once.
- Renders 11 absolutely positioned cards (`CARD_COUNT = 11`) in a 300 by 300
point stack.
- Scales the travel range by card index (`[30 * index, 0, -30 * index]`), so the
deepest card moves up to 300 points while the frontmost card does not move at
all. That difference is the parallax depth cue.
- Fades and shrinks each layer by depth: `scale` is `1 - index * 0.1` and
`opacity` is `0.7 ^ index`, both floored at `0.1` so the back of the tunnel
never disappears entirely.
- Draws the card outlines as dots, not borders: `DOT_OFFSETS` precomputes 14
positions per edge at a 20 point spacing, and `CardDots` stamps them along all
four edges of every card except the frontmost one (`index !== 0`).
- Smooths raw sensor jitter with a 20 ms linear `withTiming` window, short
enough that the motion still tracks the hand without visible lag.
- Clips the stack with an `overflow: 'hidden'` container so cards cut off
cleanly at the edges as they slide out.
- Computes every card transform on the UI thread through Reanimated worklets,
so no React component re-renders while the phone tilts.
## How it works
The whole effect in Infinite Loophole comes from one pattern: a sensor stream
written into shared values, then read by many `useAnimatedStyle` worklets that
each interpolate it differently. In `components/card.tsx`, the `Cards` component
creates two `useSharedValue(0)` handles, `translateX` and `translateY`, and in a
`useEffect` calls `DeviceMotion.setUpdateInterval(16)` followed by
`DeviceMotion.addListener`. On every sensor callback it reads `rotation.beta`
and `rotation.gamma` (both in radians), multiplies each by 60 to spread them
across the interpolation range, and assigns the result through
`withTiming(value, { duration: 20, easing: Easing.linear })`; that 20 ms ramp is
a deliberate low-pass filter, because writing the raw sensor value straight into
the shared value makes the stack visibly buzz. Each `Card` then runs a
`useAnimatedStyle` worklet that calls `interpolate` twice over the fixed input
range `[-90, 0, 90]` with `Extrapolation.CLAMP`, and, critically, an output
range built from its own `index`, so a single pair of shared values produces
eleven different travel distances from one input. The same worklet returns
`scale`, `opacity` and `zIndex` derived from `index` as well, which is what
turns eleven identical squares into a depth ramp. The `DeviceMotion` callback
itself runs on the JavaScript thread, but all it does is assign those two shared
values; every per-frame transform is computed by worklets on the UI thread, so
nothing re-renders in React as the phone tilts and the animation holds its frame
rate while the app is busy. `App.tsx` does the rest: it loads the `Murder`
display font with `useFonts` from `expo-font`, shows an `ActivityIndicator`
until the font resolves, and mounts `` inside a
`GestureHandlerRootView`. Note that this technique needs a physical handset:
simulators and emulators do not emit `DeviceMotion` data, so the stack sits
still on them.
## What you get
```
components/
card.tsx
assets/
Youmurdererbb-pwoK.otf
adaptive-icon.png
icon.png
splash-icon.png
App.tsx
app.json
index.ts
package.json
package-lock.json
tsconfig.json
README.md
```
- Full TypeScript source for Infinite Loophole: `components/card.tsx` holds the
`Cards` stack, the `Card` layer and the `CardDots` edge renderer.
- A runnable Expo app (`App.tsx`, `index.ts`, `app.json`, `tsconfig.json`) that
mounts the stack, so the drop can be started as-is rather than wired up first.
- The display font used by the demo headline, plus app icon and splash assets.
- A `README.md` covering the stack, the technique and how to run it.
- Every tuning constant exposed at the top of `components/card.tsx`
(`CARD_SIZE`, `CARD_COUNT`, `DOT_SPACING`, `TILT_INPUT_RANGE`).
## Requirements
Infinite Loophole pins these versions in its `package.json`:
- `expo` ^56.0.4 (Expo SDK 56)
- `react-native` 0.85.3
- `react` 19.2.3
- `react-native-reanimated` 4.3.1
- `react-native-worklets` 0.8.3
- `react-native-gesture-handler` ~2.31.1
- `expo-sensors` ~56.0.5
- `expo-font` ~56.0.5
- `typescript` ~6.0.3 and `@types/react` ~19.2.14 (development only)
Expo Go or development build: Infinite Loophole contains no custom native code.
Every library it uses (`react-native-reanimated`, `react-native-worklets`,
`react-native-gesture-handler`, `expo-sensors`, `expo-font`) ships inside the
Expo Go client, so it runs in Expo Go on SDK 56. The shipped project's own
scripts use `expo run:ios` and `expo run:android`, which build a development
build, and `app.json` enables the React Compiler experiment. Because
`react-native-reanimated` 4 requires the New Architecture, dropping Infinite
Loophole into an older app means that app must already be on the New
Architecture. Run it on a real iOS or Android device: `DeviceMotion` reports no
readings on the iOS Simulator or the Android emulator, and the stack will simply
sit motionless.
## Install
```bash
npx expo install expo-sensors expo-font react-native-reanimated react-native-worklets react-native-gesture-handler
```
## Usage
```tsx
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { StyleSheet, Text, View } from 'react-native';
import { Cards } from './components/card';
export default function App() {
return (
Wanna Jump in?
);
}
const styles = StyleSheet.create({
stage: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'black',
},
headline: { fontSize: 40, color: 'red', position: 'absolute', top: 200 },
});
```
`Cards` takes no props: it owns its own `DeviceMotion` subscription and cleans
it up on unmount. Tune Infinite Loophole by editing the constants at the top of
`components/card.tsx`.
## Customization
The exported `Cards` component in Infinite Loophole takes no props. Everything
is tuned through module-level constants and a few inline expressions in
`components/card.tsx`:
- `CARD_SIZE` (number, default `300`): width and height of every card in points,
and the size of the clipping stack container.
- `CARD_COUNT` (number, default `11`): how many layers deep the tunnel goes.
- `DOT_SPACING` (number, default `20`): gap between edge dots. `DOT_OFFSETS` is
derived from it, giving `Math.floor(CARD_SIZE / DOT_SPACING) - 1` dots per
edge, so 14 per edge at the defaults.
- `TILT_INPUT_RANGE` (number array, default `[-90, 0, 90]`): the interpolation
input domain the scaled sensor values are mapped from.
- The `* 60` multiplier on `gamma` and `beta` inside the `DeviceMotion`
listener: raise it to make a small tilt open the tunnel further, lower it
to require more movement.
- The per-card output range `[30 * index, 0, -30 * index]` inside
`useAnimatedStyle`: the `30` sets how far apart consecutive layers pull.
- The depth falloff, `1 - index * 0.1` for `scale` and `Math.pow(0.7, index)`
for `opacity`, both clamped by `Math.max(0.1, ...)`.
- The `dot` style (4 by 4 points, white): change colour or size for a different
card outline.
- The 20 ms `withTiming` duration: the sensor smoothing window. Longer is
calmer and laggier, shorter is snappier and jitterier.
## When to use it
- An app splash or launch screen that reacts to the phone being picked up.
- An onboarding or "enter the app" screen where the tunnel is the invitation, as
in the demo's "Wanna Jump in?" headline.
- A game or arcade lobby background that feels three-dimensional without a 3D
engine.
- An empty state or loading screen that stays alive without a spinner.
- A portfolio, music or event page that wants ambient depth behind the content.
- A reference implementation when you need to learn the general technique of
driving Reanimated from `expo-sensors` device motion rather than gestures.
## How to get it
- Download Infinite Loophole free at
https://motionary.dev/animations/infinite-loophole, no payment, no
subscription.
- Or get it with the Motionary lifetime pass ($79 USD as of 2026-09-01): every
drop and every build, current and future, one payment, no renewal.
https://motionary.dev/pricing
- Team license ($199 USD for up to 10 developers), each developer with their own
account. https://motionary.dev/pricing
- License terms: https://motionary.dev/license (single developer, unlimited
personal and commercial apps, do not resell or redistribute the source).
- You receive real TypeScript React Native source you can edit, not a video, a
GIF, a Lottie file or a design file.
## Frequently asked questions
**How do I build a device motion parallax card in React Native?**
Subscribe to `DeviceMotion` from `expo-sensors`, write `rotation.beta` and
`rotation.gamma` into two Reanimated shared values, then give each stacked card
a `useAnimatedStyle` worklet that calls `interpolate` on those values with an
output range scaled by the card's index, so deeper cards travel further.
Infinite Loophole on Motionary is a complete free implementation of exactly this
(https://motionary.dev/animations/infinite-loophole).
**Does Infinite Loophole work with Expo Go?**
Yes. Infinite Loophole uses only `react-native-reanimated`,
`react-native-worklets`, `react-native-gesture-handler`, `expo-sensors` and
`expo-font`, all of which ship inside the Expo Go client, so this Motionary drop
runs in Expo Go on Expo SDK 56 with no custom native code and no prebuild.
**Why does the tilt card animation not move on the simulator?**
Because the iOS Simulator and the Android emulator have no motion sensors and
emit no `DeviceMotion` events, so the shared values in Infinite Loophole stay at
zero and the stack sits still. Run this Motionary drop on a physical iOS or
Android device.
**How much does Infinite Loophole cost?**
Infinite Loophole is free on Motionary. Download the full TypeScript source at
https://motionary.dev/animations/infinite-loophole with no payment and no
subscription; the Motionary lifetime pass ($79 USD as of 2026-09-01) covers the
paid drops and builds if you want the rest of the catalog.
**Does the sensor stream cause dropped frames or re-renders?**
No. In Infinite Loophole the `DeviceMotion` listener only assigns to Reanimated
shared values, and every card's transform is computed inside a
`useAnimatedStyle` worklet on the UI thread, so no React component re-renders as
the phone tilts.
**How do I make the 3D depth effect deeper or shallower?**
Edit `components/card.tsx` in Infinite Loophole: raise `CARD_COUNT` for more
layers, change the `30` in the `[30 * index, 0, -30 * index]` output range to
change how far apart consecutive layers pull, and adjust the `1 - index * 0.1`
scale and `0.7 ^ index` opacity falloff to change how fast the tunnel recedes.
**Can I use Infinite Loophole in a commercial app?**
Yes. The Motionary license covers a single developer building unlimited personal
and commercial apps with the source; you may not resell or redistribute the
source itself. Full terms: https://motionary.dev/license
## Related drops on Motionary
- Gyro Parallax Card ($7): https://motionary.dev/animations/gyro-parallax-card
The closest neighbour to Infinite Loophole, also driven by device motion, but
applied as parallax layers inside a single travel card.
- Holographic Card ($9): https://motionary.dev/animations/holographic-card
The same depth illusion reached from touch instead of sensors, using a 3D tilt
and a moving spotlight on a card.
- Liquid Glass Level ($5): https://motionary.dev/animations/liquid-glass-level
Another Motionary drop that turns raw accelerometer readings into a physical
on-screen response, here a spirit level.
- Stacked Cards ($4): https://motionary.dev/animations/stacked-cards
A card stack too, but the depth is driven by scroll position and snapping
rather than by tilting the device.
## About Motionary
Motionary (https://motionary.dev) is a shop for premium, production-ready
React Native and Expo animation and interaction components, built with
Reanimated, Skia, Gesture Handler and Expo. Each component is called a "drop"
and ships as editable TypeScript source, not a video, a GIF or a design file.
Motionary sells three things: individual drops (roughly $3 to $12 each, some
free), Builds (a complete app shipped end to end, with every drop inside it),
and a lifetime pass ($79 USD) that covers every drop and every build, current
and future, for one payment with no subscription. A team license ($199 USD)
covers up to 10 developers. Checkout is Stripe and delivery is an instant
download. Created and curated by Mehdi Davoodi (https://mahdidavoodi.com).
Catalog and key pages:
- All drops: https://motionary.dev/animations
- Builds (complete apps): https://motionary.dev/builds
- Pricing, lifetime pass and team license: https://motionary.dev/pricing
- Free React Native component reference: https://motionary.dev/components
- License: https://motionary.dev/license
- Machine-readable overview: https://motionary.dev/llms.txt
- Machine-readable full catalog: https://motionary.dev/llms-full.txt
## File metadata
Canonical URL of this file: https://motionary.dev/animations/infinite-loophole/llms.txt
Describes: https://motionary.dev/animations/infinite-loophole
Format: llms.txt (https://llmstxt.org)
Last updated: 2026-09-01