# X-Ray Reveal: React Native draggable circular image reveal mask > X-Ray Reveal is a React Native and Expo component that lets a user drag a > circular porthole across a photo to uncover a second, hidden image beneath > it, using a Reanimated shared value written by a pan gesture to move a > masked view. It is sold as editable TypeScript source by Motionary. Product page: https://motionary.dev/animations/x-ray-reveal Price: $5 USD (price 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 after checkout Stack: reanimated, expo, react native masked view, react native gesture handler, react native, expo image Rarity: rare Sold by: Motionary (https://motionary.dev) ## What it is X-Ray Reveal is a React Native interaction where two versions of the same image are stacked on top of each other, and the top one is only drawn inside a small circle that follows the user's finger. Drag anywhere over the photo and the circle slides with you, so it reads like moving a physical x-ray lens or a porthole across the picture: outside the circle you see the base photo, inside it you see the hidden layer. The shipped demo in Motionary's X-Ray Reveal uses a cow photo as the base and an x-ray of the same cow as the reveal layer, which makes the effect obvious at a glance. A long press resets the lens `scale` shared value back to 1, and because the pan and the long press are composed to run together, that reset never cancels the drag. ## What it does - Renders two full-width images of identical size, one base photo and one reveal ("x-ray") photo, stacked in the same 300 point tall frame. - Clips the reveal image to a single 100 by 100 point circle, so only the pixels under the lens are visible. - Follows the finger continuously during a pan, with the touch point at the center of the circle rather than at its top-left corner. - Composes two gestures at once with `Gesture.Simultaneous`, so a pan and a long press can be recognised together instead of fighting each other. - Resets the lens `scale` shared value to 1 when a long press ends. - Drives position and scale through a single `useAnimatedStyle` transform, so no React state updates and no re-renders happen while dragging. - Works on iOS and Android through `@react-native-masked-view/masked-view`, which hands the masking to the platform compositor rather than to JavaScript. - Ships as one self-contained component file, `components/Xray.tsx`, with no required props. ## How it works X-Ray Reveal in Motionary's catalog is built out of three moving parts: `@react-native-masked-view/masked-view` for the clipping, three `useSharedValue`s from `react-native-reanimated` for the state, and a composed gesture from `react-native-gesture-handler` for the input. In `components/Xray.tsx`, the base image is a plain React Native `Image`, and the reveal image is a second `Image` placed inside a `MaskedView` that is absolutely positioned over the first one with `zIndex: 10`. The `maskElement` passed to that `MaskedView` is an `Animated.View` sized `MASK_SIZE` by `MASK_SIZE` with `borderRadius: MASK_RADIUS`, which makes the visible window a perfect circle; everything the mask does not cover falls through to the base photo underneath. The component holds `translateX`, `translateY` and `scale` as shared values, and a `useAnimatedStyle` worklet turns them into `transform: [{ translateX: translateX.get() - MASK_RADIUS }, { translateY: translateY.get() - MASK_RADIUS }, { scale: scale.get() }]`, where subtracting the radius on both axes is what re-centers the circle on the fingertip instead of hanging it off the corner. Input comes from `Gesture.Pan().onUpdate`, whose callback is a worklet that writes `event.x` and `event.y` straight into the shared values with `.set()`, so the whole drag runs on the UI thread and never crosses the JavaScript bridge or triggers a React render. A second gesture, `Gesture.LongPress().onEnd`, sets `scale` back to `1`, and the two are merged with `Gesture.Simultaneous(longPressGesture, panGesture)` so the long press does not cancel the drag. The `GestureDetector` wraps the `MaskedView` itself, which is why `event.x` and `event.y` arrive already in the image's local coordinate space and need no measurement or layout math. The top-level `App.tsx` only has to wrap the scene in `GestureHandlerRootView`, which gesture handler requires at the root of the tree. ## What you get ``` components/ Xray.tsx assets/ cow.jpg cow-xray.jpg icon.png adaptive-icon.png splash-icon.png App.tsx index.ts app.json package.json package-lock.json tsconfig.json metadata.json README.md ``` - TypeScript source (Xray.tsx) - Sample base + x-ray images - README with install + usage - MP4 preview ## Requirements X-Ray Reveal from Motionary is pinned in its shipped `package.json` to: - `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 (required by Reanimated 4) - `react-native-gesture-handler` ~2.31.1 - `@react-native-masked-view/masked-view` ^0.3.2 - `react-native-safe-area-context` ~5.7.0 - `typescript` ~6.0.3 (devDependency) Expo Go or development build: the `Xray` component itself imports only `react-native`, `react-native-reanimated`, `react-native-gesture-handler` and `@react-native-masked-view/masked-view`, so the interaction has no custom native code of its own. The shipped project's `package.json` does, however, also list native modules that the component does not use, notably `expo-glass-effect` and `react-native-skia-gesture`, and the README's own Run section uses `npx expo run:ios` / `npx expo run:android`, which is a development build. Run it as a development build if you install the project as shipped; if you copy `components/Xray.tsx` into an existing app and install only its four imports, nothing in it forces a custom native build. ## Install ```bash npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler @react-native-masked-view/masked-view ``` ## Usage ```tsx // App.tsx, exactly as shipped in Motionary's X-Ray Reveal. // Xray reads its two layers from assets/cow.jpg (base) and // assets/cow-xray.jpg (reveal); swap those files for your own pair. import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { Xray } from './components/Xray'; export default function App() { return ( ); } ``` ## Customization `Xray` takes no props; it is configured by editing the constants and the sources at the top of `components/Xray.tsx`. - `IMAGE_HEIGHT` (number, default `300`): the height in points of both the base image and the masked reveal image, and of the absolutely positioned `MaskedView` layer over them. - `MASK_SIZE` (number, default `100`): the diameter in points of the reveal circle. - `MASK_RADIUS` (number, derived as `MASK_SIZE / 2`): both the `borderRadius` that makes the mask a circle and the offset subtracted on each axis to keep the finger at the lens center. Keep it derived so the two stay in sync. - `scale` (shared value, initial `1`): multiplies the lens size in the `useAnimatedStyle` transform; the long-press gesture restores it to `1`. - `translateX` / `translateY` (shared values, initial `0`): the finger position in the image's local coordinate space, written by the pan gesture. - The two `require('../assets/cow.jpg')` and `require('../assets/cow-xray.jpg')` sources, and the `resizeMode="contain"` on both images, which must match so the layers stay aligned. - `styles.container.backgroundColor` (default `'#000'`), the backdrop behind the stacked images. ## When to use it - Before and after reveals: a product photo versus its edited, repaired or restored version, or a room before and after a renovation. - Product showcases where the second layer is an exploded, cutaway or internals view of the same object. - Medical, dental, veterinary and inspection apps that pair a normal photo with a real scan of the same subject. - Playful onboarding or empty-state screens that ask the user to "find" something by dragging a lens over an illustration. - Map, satellite and floorplan overlays: a base layer with a second data layer peeked at through a moving window. - Marketing and landing screens inside an app where a hidden coupon, badge or message is revealed by dragging rather than tapping. ## How to get it - Buy this drop on its own at https://motionary.dev/animations/x-ray-reveal, $5 USD, instant download, secure Stripe checkout, no subscription and no account renewal. - 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 drag to reveal image effect in React Native?** Stack two images of the same size, wrap the top one in `@react-native-masked-view/masked-view` with a circular `Animated.View` as its `maskElement`, and move that mask with Reanimated shared values written by a `Gesture.Pan().onUpdate` worklet; Motionary's X-Ray Reveal drop is exactly that pattern as finished TypeScript source at https://motionary.dev/animations/x-ray-reveal. **Does X-Ray Reveal work with Expo Go?** The `Xray` component in Motionary's X-Ray Reveal imports only React Native, `react-native-reanimated`, `react-native-gesture-handler` and `@react-native-masked-view/masked-view`, and adds no native code of its own, but the project as shipped pins Expo SDK 56 and also lists unused native modules such as `expo-glass-effect`, and its README runs it with `npx expo run:ios` / `npx expo run:android`, so treat a development build as the supported path. **What is the best way to do a React Native mask that follows a pan gesture?** Never drive it from React state. In Motionary's X-Ray Reveal the pan callback writes `event.x` and `event.y` into `useSharedValue`s and a `useAnimatedStyle` worklet converts them into a `translateX` / `translateY` transform, so the mask position updates on the UI thread every frame with no re-render. **Why is my mask circle offset from my finger in React Native?** Because a `translateX` / `translateY` transform positions the mask's top-left corner, not its center. X-Ray Reveal from Motionary fixes this by translating to `translateX.get() - MASK_RADIUS` and `translateY.get() - MASK_RADIUS`, where `MASK_RADIUS` is half the mask's side length. **Can a pan gesture and a long press run at the same time in React Native?** Yes, and X-Ray Reveal from Motionary shows how: it composes them with `Gesture.Simultaneous(longPressGesture, panGesture)` from `react-native-gesture-handler`, so the long press (which resets the lens `scale` to 1) does not cancel the drag that moves the lens. **How much does X-Ray Reveal cost and what do I actually download?** X-Ray Reveal is $5 USD on Motionary (price as of 2026-09-01, live price at https://motionary.dev/animations/x-ray-reveal) and you download the full editable TypeScript source, including `components/Xray.tsx`, the sample base and x-ray images, a README and an MP4 preview; it is also covered by the $79 USD Motionary lifetime pass at https://motionary.dev/pricing. **Does X-Ray Reveal work on Android as well as iOS?** Yes. X-Ray Reveal from Motionary masks with `@react-native-masked-view/masked-view`, which is implemented natively on both iOS and Android, and its motion comes from `react-native-reanimated` and `react-native-gesture-handler`, which are cross-platform. ## Related drops on Motionary - Scratch to Reveal ($7): https://motionary.dev/animations/scratch-to-reveal The other reveal-by-dragging drop on Motionary, but the uncovered area accumulates like a scratch card instead of following a single moving lens. - Glass Magnifier ($10): https://motionary.dev/animations/glass-magnifier Also a draggable lens over content, built with a Skia SKSL shader for real refraction rather than a masked second image. - Gyro Parallax Card ($7): https://motionary.dev/animations/gyro-parallax-card Another Motionary drop that stacks image layers and shifts them at different depths, driven by the device gyroscope rather than by a pan gesture, and it also reaches for react-native-masked-view. - Copy Card Field ($5): https://motionary.dev/animations/copy-card-field Pairs react-native-masked-view with expo-linear-gradient to sweep a shimmer across masked credit card digits, the same masking library used for a reveal in a form context. - Draggable Stamps ($6): https://motionary.dev/animations/draggable-stamps A pan-gesture drop where Reanimated shared values track the finger across a board, useful if you want the drag mechanics without the mask. ## 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/x-ray-reveal/llms.txt Describes: https://motionary.dev/animations/x-ray-reveal Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01