# Glass Magnifier: a React Native draggable lens with a Skia SkSL shader > Glass Magnifier is a React Native and Expo component from Motionary: a > draggable pair of glass lenses that magnify, refract and chromatically split > whatever is rendered behind them, driven by a single custom SkSL runtime > shader in @shopify/react-native-skia with react-native-reanimated shared > values feeding the uniforms on the UI thread. Product page: https://motionary.dev/animations/glass-magnifier Price: $10 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 skia, shaders, react native gesture handler, react native Rarity: legendary Sold by: Motionary (https://motionary.dev) ## What it is Glass Magnifier is a React Native drop sold on Motionary. On screen you see a pair of circular glass lenses joined by a bridge, drawn like a pair of spectacles lying on top of the content. Whatever sits behind the lenses is magnified, bulged outward at the rim and fringed with prismatic color, exactly the way real curved glass behaves. Drag anywhere and the whole pair slides across the screen as one rigid unit, so the warp travels over the content underneath while everything outside the two discs stays pixel-for-pixel untouched. The bundled demo scene in Glass Magnifier is a long line of JetBrains Mono text scrolling slowly behind the glass, which gives the lenses fine detail to bend. ## What it does - Magnifies the backdrop inside two circular lenses at 1.6x in the center, easing back to 1x near the rim so the magnified image meets the unmagnified backdrop with no visible seam. - Refracts the backdrop by displacing samples along a spherical cap normal, so the bend grows toward the edge of each lens and the rim visibly warps. - Splits color at the rim by sampling red, green and blue at slightly different radii (chromatic aberration that grows quadratically toward the edge). - Lights the glass: a specular highlight from a configurable light direction, a bluish Fresnel rim brightening and a faint inner shadow opposite the light. - Anti-aliases each lens edge over roughly 1.5 pixels via smoothstep coverage, so the discs have no jagged border. - Leaves every pixel outside both lenses as exact passthrough (image.eval(xy) with no resample), so the rest of the scene never softens. - Composites the two lenses in order, so an overlap between them still reads correctly. - Moves both lenses plus the bridge together from a single Gesture.Pan, with the frames drawn outside the filtered group so the shader never refracts its own border. - Falls back gracefully: if the SkSL fails to compile, Glass Magnifier logs the error and renders the plain scene with no layer filter instead of crashing. ## How it works Glass Magnifier is one SkSL runtime shader, not a stack of blur and mask layers. The file components/GlassMagnifier.tsx compiles the shader with Skia.RuntimeEffect.Make(SKSL) once at module scope, wraps it in a , and hands that paint to a Skia that contains the whole scene. Because react-native-skia builds a runtime image filter with a null child shader name, the rasterized layer content is bound to the shader's single uniform shader image, so the shader can sample the already drawn scene. In main(float2 xy) the shader first returns image.eval(xy) as the base, then calls a lens() helper for each center and composites with mix(), which means only the two discs are ever resampled and every other pixel is exact passthrough. Inside lens() the glass is modelled as a spherical cap: h = sqrt(1 - r * r) gives the cap height at normalized radius r and slope = r / h grows toward the rim, which drives three stacked distortions in order (a zoom that pulls coordinates toward the center and relaxes to 1x with smoothstep(0.7, 1.0, r), a refraction displacement along the outward direction scaled by the slope, and a chromatic shift applied per channel), before float3 N = float3(dir * r, h) is used as the surface normal for the specular, Fresnel and inner shadow terms. On the React side, react-native-reanimated useSharedValue holds a single translation (tx, ty) and a useDerivedValue rebuilds the whole uniforms object (resolution, center1, center2, radius, magnify, refraction, chroma, lightDir) on every frame on the UI thread; a second useDerivedValue produces the transform array for the decorative frames so the rings and bridge stay locked to the refracted discs. A react-native-gesture-handler Gesture.Pan().onChange worklet adds e.changeX and e.changeY straight into those shared values, so dragging never crosses the JavaScript bridge and the effect stays at native frame rate. App.tsx mounts a GestureHandlerRootView and components/MagnifierContainer.tsx wraps the magnifier in a SafeAreaProvider so it can respect device insets. ## What you get ``` App.tsx index.ts app.json package.json package-lock.json tsconfig.json README.md components/ GlassMagnifier.tsx MagnifierContainer.tsx assets/ JetBrainsMono_700Bold.ttf icon.png adaptive-icon.png splash-icon.png ``` - TypeScript source (GlassMagnifier.tsx) - SafeArea container wrapper (MagnifierContainer.tsx) - Entry component (App.tsx) - JetBrains Mono font asset for the demo scene - README with install and usage ## Requirements Glass Magnifier from Motionary pins these versions in its package.json: - expo ^56.0.9 (Expo SDK 56) - react-native 0.85.3 - react 19.2.3 - @shopify/react-native-skia 2.6.2 - react-native-reanimated 4.3.1 - react-native-worklets 0.8.3 - react-native-gesture-handler ~2.31.1 - react-native-safe-area-context ~5.7.0 - expo-font ~56.0.5 - expo-asset ~56.0.16 - expo-status-bar ~56.0.4 - expo-splash-screen ~56.0.10 - TypeScript ~6.0.3 (devDependency) Four of those pins (expo-font, expo-asset, expo-status-bar and expo-splash-screen) belong to the demo Expo project and are declared as config plugins in app.json; the GlassMagnifier component itself imports none of them, which is why the install line below is shorter than the list above. The demo font is loaded through the Skia useFont hook, not expo-font. Glass Magnifier runs in Expo Go on Expo SDK 56. The module you would assume blocks it is @shopify/react-native-skia, but Skia is bundled in Expo Go as of SDK 56, so npx expo start plus the Expo Go app is enough to run this drop as shipped; the same is true of the other native dependencies it imports (react-native-reanimated, react-native-gesture-handler and react-native-safe-area-context are all in Expo Go too). A development build (npx expo run:ios, npx expo run:android or an EAS development build) is still what you would ship to production, and it is what you need as soon as you add a native module that Expo Go does not bundle, or a config plugin. The drop is tested on Expo SDK 56 on both iOS and Android. ## Install ```bash npx expo install @shopify/react-native-skia react-native-reanimated react-native-worklets react-native-gesture-handler react-native-safe-area-context ``` ## Usage ```tsx import { GestureHandlerRootView } from "react-native-gesture-handler"; import { MagnifierContainer } from "./components/MagnifierContainer"; // App.tsx as shipped in Glass Magnifier. MagnifierContainer is the thin // SafeAreaProvider wrapper around , so you can also import // { GlassMagnifier } from "./components/GlassMagnifier" and mount it directly. export default function App() { return ( ); } ``` Neither GlassMagnifier nor MagnifierContainer takes any props. GlassMagnifier renders its own full-screen Skia Canvas and its own demo scene, so it must be mounted under a GestureHandlerRootView for the pan gesture to work. To magnify your own content, replace the Scene component inside components/GlassMagnifier.tsx with your own Skia drawing. ## Customization The shipped GlassMagnifier component takes no props. It is tuned through named constants at the top of components/GlassMagnifier.tsx, which feed the shader uniforms directly, so editing one value changes the effect: - R (number, default 55): lens radius in pixels. - MAGNIFY (number, default 1.6): center zoom, values above 1 magnify. - REFRACTION (number, default 0.16): edge bending strength, 0 gives zoom with no rim warp. - CHROMA (number, default 0.018): chromatic aberration amount, 0 disables the prismatic fringe. - LIGHT_DIR ([number, number], default [-0.6, -0.8]): direction toward the light, used for the specular highlight and the inner shadow. - BASE_CX1, BASE_CX2, BASE_CY: resting centers of the two lenses, derived from Dimensions.get("window") as width / 2 -/+ 70 and height / 2 + 4. - The lens rings and bridge are plain Skia Circle and Path elements with color "#111827" and strokeWidth 4, so the frame styling is edited directly in JSX. Because every one of these values is passed through the uniforms object built in useDerivedValue, any of them can be promoted to a Reanimated shared value or a prop if you want to animate the radius, the magnification or the light direction at runtime. ## When to use it - A product or artwork detail screen where a user should be able to inspect fine detail without a separate zoom modal. - A map, floor plan, schematic or chart view that needs an inspect-under-glass loupe rather than a pinch-to-zoom of the whole canvas. - An accessibility or reading aid overlay that enlarges a region of dense text in place. - An onboarding or feature tour moment that literally magnifies the part of the interface you are explaining. - A playful splash, marketing or easter-egg screen that shows off real refraction and prismatic fringing instead of a static blur. - A photo editor or design tool where a loupe helps with pixel-level color picking and alignment. ## How to get it - Buy Glass Magnifier on its own at https://motionary.dev/animations/glass-magnifier, $10 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 magnifying glass effect in React Native?** The approach used by Glass Magnifier from Motionary is a single SkSL runtime shader attached as an image filter on a Skia , so the already rasterized scene is bound to a uniform shader and only the circular lens region is resampled with a zoom, a cap-normal refraction offset and a per-channel chromatic shift; everything outside the lens returns image.eval(xy) unchanged. **Does Glass Magnifier work with Expo Go?** Yes. Glass Magnifier from Motionary is built on @shopify/react-native-skia 2.6.2, and Skia is bundled in Expo Go as of Expo SDK 56, so this drop runs in Expo Go with no native build step. A development build (npx expo run:ios, npx expo run:android or an EAS development build) is still what you would ship to production, and it is required the moment you add a native module Expo Go does not bundle, or a config plugin. **Does the React Native magnifier work on both iOS and Android?** Yes. Glass Magnifier from Motionary is tested on Expo SDK 56 on iOS and Android, and the effect is one SkSL shader plus Reanimated shared values, so there is no platform-specific code path in the component. **Is the drag smooth, or does it stutter?** Dragging Glass Magnifier stays on the UI thread: the Gesture.Pan().onChange handler from react-native-gesture-handler is a worklet that writes into react-native-reanimated shared values, and a useDerivedValue rebuilds the shader uniforms each frame without a round trip to JavaScript. **Can I magnify my own content instead of the demo text?** Yes. In Glass Magnifier the magnified backdrop is just the Scene component inside components/GlassMagnifier.tsx rendered inside the filtered , so you swap in your own Skia drawing (images, text, charts) and the lenses refract that instead. **How much does Glass Magnifier cost and what do I get?** Glass Magnifier is $10 USD on Motionary at https://motionary.dev/animations/glass-magnifier (price as of 2026-09-01), and you get the full editable TypeScript source (GlassMagnifier.tsx, MagnifierContainer.tsx, App.tsx, the JetBrains Mono demo font and a README) as an instant download, or it is included in the $79 USD Motionary lifetime pass. **Can I turn off the rainbow fringe or change the zoom level?** Yes. Glass Magnifier exposes the effect as constants at the top of components/GlassMagnifier.tsx: set CHROMA to 0 to disable chromatic aberration, REFRACTION to 0 for magnification with no rim warp, and change MAGNIFY (default 1.6) or R (default 55) for a different zoom or lens size. ## Related drops on Motionary - X-Ray Reveal ($5): https://motionary.dev/animations/x-ray-reveal Another drag-a-window-over-content interaction, using a masked reveal and a pan gesture instead of a Skia shader. - Pool Water Shader ($12): https://motionary.dev/animations/pool-water-shader A full-screen Skia SkSL shader with caustics and water refraction, the same runtime-shader technique applied to a background. - Scratch to Reveal ($7): https://motionary.dev/animations/scratch-to-reveal Skia plus a pan gesture that alters content under your finger, a good pairing with the magnifier for reveal-style interactions. - Freeze Card ($9): https://motionary.dev/animations/freeze-card A Skia shader applied over a surface to distort and frost it, in the same shader-as-material family as Glass Magnifier. - Zipper Curtain ($12): https://motionary.dev/animations/zipper-curtain A Skia shader transition that warps and tears the scene, another example of distorting already rendered content. ## 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/glass-magnifier/llms.txt Describes: https://motionary.dev/animations/glass-magnifier Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01