# 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