# Dot Wave Slider: React Native snapping slider with a GPU dot-field track > Dot Wave Slider is a React Native and Expo slider component whose track is a > field of tiny dots drawn by a single Skia SkSL runtime shader: drag the thumb > between six snap stops and, at the end, a purple wave sweeps across the dots > while they twinkle in place. It is sold by Motionary as editable TypeScript > source built on react-native-reanimated, @shopify/react-native-skia, > react-native-gesture-handler and expo-haptics. Product page: https://motionary.dev/animations/dot-wave-slider 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 Dot Wave Slider is a React Native slider with a rounded gray track, a small white pill thumb, and six discrete detents drawn as dots along the track. The part of the track behind the thumb is not a solid fill: it is a grid of tiny rounded-square dots, six rows deep, rendered by one Skia shader. Drag the thumb with your finger, or tap anywhere on the track and the thumb glides to the touch; on release it springs to the nearest of the six stops with a light haptic tick. When the thumb lands on the last stop, the detent dots dissolve away and a purple wave sweeps across the dot field from the thumb backwards, then holds while each dot twinkles on its own phase. Drag back off the end and the purple fades out by position rather than snapping off. Dot Wave Slider draws "Faster" and "Smarter" labels above the two ends of the track itself, in the shape of a model-quality slider. ## What it does - Six discrete snap stops (`STOPS = 6`); release snaps to the nearest one with a `withSpring` at damping 20, stiffness 320, mass 0.7. - Free dragging while the finger is down: the thumb tracks the finger anywhere along the track, with no quantising until release. - Grab versus tap are distinguished in `onBegin`: a touch within half a thumb width plus 4px picks the thumb up at its grab offset, anything further away springs the thumb to the touch point. - Zero dead zone on grab, because the pan gesture uses `.minDistance(0)` instead of the default activation distance. - Light impact haptics through `expo-haptics` on both grab and release. - The entire dot field is one `Skia.RuntimeEffect` SkSL shader drawn in a single `` inside one ``, so per-dot work never becomes per-dot React elements. - A ragged wavefront: each dot's reveal is offset by a per-cell `hash` dither of up to 38px, over a 34px feather, so the front reads as a scattering edge rather than a straight vertical line. - Per-dot twinkle driven by Skia's `useClock`, so the field stays alive after the wave has finished instead of visibly stopping. - Distance falloff: dots fade toward the track gray the further they sit from the thumb. - The dot field extends underneath the thumb, so dots emerge from beneath it already at full intensity; the thumb is drawn on top and hides the seam. - Detent dots live in a `` whose opacity cross-fades (400ms out, 300ms back in) as the wave takes over and gives way again. - Re-arming logic: the wave only replays once the thumb has dropped below the final segment, so nudging off the end and back continues the same play. - `onValueChange` fires once per release with the settled value in [0, 1]. - Works on iOS and Android. ## How it works Dot Wave Slider draws its whole track inside one `@shopify/react-native-skia` `` in `components/DotWaveSlider.tsx`. A `Skia.RuntimeEffect.Make(...)` compiles an SkSL fragment shader once at module scope, and that shader is painted through a `` clipped to a rounded rect (`Skia.RRectXY`), so the dot field is a single draw call rather than hundreds of views. Inside `main(float2 xy)` the shader maps each pixel to a grid `cell` with `floor(p / pitch)`, builds a rounded-square signed-distance mask for the dot in that cell, and mixes a track gray toward purple by `reveal * falloff * (0.55 + 0.45 * twinkle) * mask * dim`, so every per-dot calculation happens on the GPU. The thumb position is a `react-native-reanimated` `useSharedValue`, and `thumbLeft` is a `useDerivedValue` that clamps it so a springy overshoot cannot push the thumb past either end of the track. The only per-frame JavaScript is one `useDerivedValue` uniforms worklet, which runs on the UI thread and feeds `time` (from Skia's `useClock`), `front`, `limit`, `fade`, `dim` and the grid geometry into the shader; the JS thread is never touched during a drag. Gestures come from `react-native-gesture-handler`: a `Gesture.Pan()` with `.minDistance(0)` and a vertical `hitSlop`, whose `onBegin` decides between grabbing the thumb and gliding it to a tap, whose `onUpdate` converts the touch x into a 0 to 1 value, and whose `onFinalize` rounds to the nearest of six stops and springs there. A `useAnimatedReaction` watches the value and arms the wave the moment it reaches the end, resetting `wave` to 0 and driving it to 1 with `withTiming` over 1800ms on `Easing.inOut(Easing.sin)`; that `front` uniform is what sweeps the reveal across the field. A separate `dim` derived value tracks the thumb across the final segment so dragging off the end fades the purple out by position instead of cutting it. Haptics cross the thread boundary safely because the gesture worklets call `scheduleOnRN` from `react-native-worklets` to hop back to the React Native thread before invoking `Haptics.impactAsync` and the `onValueChange` callback. ## What you get ``` App.tsx index.ts app.json babel.config.js tsconfig.json package.json package-lock.json README.md components/ Container.tsx DotWaveSlider.tsx assets/ icon.png adaptive-icon.png splash-icon.png ``` - TypeScript source (DotWaveSlider.tsx) - SkSL runtime shader for the dot field - Container/demo screen (Container.tsx) - README with install + usage - MP4 preview ## Requirements Dot Wave Slider from Motionary is built and pinned against these versions in the archive's `package.json`: - `expo` ^56.0.4 (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 - `expo-haptics` ~56.0.3 - `react-native-safe-area-context` ~5.7.0 - `expo-status-bar` ~56.0.4 - `typescript` ~6.0.3 (devDependency) Expo Go or development build: Dot Wave Slider runs in Expo Go on Expo SDK 56. The module you would assume blocks it is `@shopify/react-native-skia`, and that one is bundled in Expo Go as of SDK 56, so you can open the drop in Expo Go without building anything. A development build (`npx expo run:ios`, `npx expo run:android`, or an EAS development build) is still what you 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. Reanimated 4 also requires `react-native-worklets`, which `babel-preset-expo` wires up automatically when the package is installed. ## Install ```bash npx expo install @shopify/react-native-skia react-native-reanimated react-native-worklets react-native-gesture-handler expo-haptics react-native-safe-area-context ``` ## Usage ```tsx import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { StyleSheet, View } from 'react-native'; import { DotWaveSlider } from './components/DotWaveSlider'; export default function App() { return ( console.log('settled at', value)} /> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: 'white', justifyContent: 'center', paddingHorizontal: 28, }, }); ``` `GestureHandlerRootView` has to wrap the tree, otherwise the pan gesture never activates. ## Customization The `DotWaveSlider` component from Motionary exposes two props (`DotWaveSliderProps`): - `initialValue?: number` (default `1`): starting value in [0, 1]. It is clamped and rounded to the nearest of the six stops on mount. - `onValueChange?: (value: number) => void`: called with the settled value once, when the user releases the thumb. Dot Wave Slider renders at a fixed width of `280`, held in a `useState(280)` inside `components/DotWaveSlider.tsx`; the `onLayout` line that would measure the parent is commented out, so change that number or re-enable `onLayout` to fit a different container. Everything else is a named constant at the top of `components/DotWaveSlider.tsx`, which is the point of shipping the source: - `STOPS` (`6`): number of detents, and therefore the snap resolution. - `SNAP_SPRING` (`{ damping: 20, stiffness: 320, mass: 0.7 }`): the release snap feel. - `TRACK_HEIGHT` (`30`), `THUMB_WIDTH` (`22`), `THUMB_HEIGHT` (`28`), `THUMB_RADIUS` (`8`), `PAD` (`12`, canvas padding so the thumb is not clipped). - `ROWS` (`6`), `PITCH` (`4.7`), `DOT_SIZE` (`3.6`): the dot grid geometry fed to the shader as uniforms. - `FEATHER` (`34`) and `DITHER` (`38`): softness of the wavefront and the per-dot random stagger that makes it ragged. - `SNAP_DOT_COLOR` (`'#9E9B9B'`) and `SNAP_END_COLOR` (`'#6D5F96'`): the detent dots and the purple endpoint. - `TRACK` and `PURPLE` in the SkSL source: the two colors the shader mixes between, as `float3` values. - The `withTiming(1, { duration: 1800, easing: Easing.inOut(Easing.sin) })` call inside the `useAnimatedReaction` controls how long the wave takes to sweep. ## When to use it - An AI model or quality selector, "Faster" to "Smarter", where the top setting should feel like it costs something. - A pricing or plan slider on a paywall, where landing on the top tier deserves a reward animation. - A settings screen control with a small number of discrete levels (brightness, intensity, sensitivity) that should snap rather than float. - An onboarding step that asks the user to pick a level and needs the maximum choice to be visibly celebrated. - A power or performance mode picker in a device or hardware companion app. - Any place a stock React Native slider looks flat and you want a track with texture that still runs at native frame rates. ## How to get it - Buy Dot Wave Slider on its own at https://motionary.dev/animations/dot-wave-slider, $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 **Does Dot Wave Slider work with Expo Go?** Yes. Dot Wave Slider from Motionary depends on `@shopify/react-native-skia`, and Skia is bundled in Expo Go as of Expo SDK 56, so the drop runs in Expo Go as it ships. Everything else it uses (Reanimated, Gesture Handler, expo-haptics) is available in a normal Expo project too. A development build (`npx expo run:ios`, `npx expo run:android`, or an EAS development build) is still what you ship to production, and it is what you need the moment you add a native module that Expo Go does not bundle, or a config plugin. **How do I build a custom animated slider in React Native?** Hold the thumb position in a Reanimated `useSharedValue`, drive it from a `react-native-gesture-handler` `Gesture.Pan()` with `.minDistance(0)` so there is no dead zone, snap on `onFinalize` with `withSpring`, and derive everything visual from that one value with `useDerivedValue`. Motionary's Dot Wave Slider is exactly this pattern with a Skia shader painting the track. **How do I add haptics to a slider in React Native?** Call `Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)` from `expo-haptics`, but remember gesture callbacks are worklets on the UI thread, so hop back first with `scheduleOnRN` from `react-native-worklets`. Dot Wave Slider from Motionary ships that exact wiring, firing a light tick on grab and on release. **Can I change the number of snap stops?** Yes. Dot Wave Slider ships as editable TypeScript, and the detent count is the `STOPS` constant (default `6`) at the top of `components/DotWaveSlider.tsx`; the snap rounding, the detent dot positions and the re-arm threshold are all derived from it. **Does Dot Wave Slider run on Android as well as iOS?** Yes. Dot Wave Slider from Motionary runs on both iOS and Android; the dot field is a Skia SkSL runtime shader, which Skia compiles on both platforms, and the gesture and spring work is Reanimated on the UI thread. **Is the dot field expensive to render?** No. In Dot Wave Slider the whole field is one `Skia.RuntimeEffect` painted in a single draw call, with reveal, twinkle, falloff and the rounded-rect signed-distance mask all evaluated per pixel on the GPU. The only per-frame JavaScript is one small `useDerivedValue` worklet feeding uniforms, so the JS thread stays idle while you drag. **How much does Dot Wave Slider cost and what do I get?** Dot Wave Slider is $10 USD on Motionary at https://motionary.dev/animations/dot-wave-slider (price as of 2026-09-01, live price on the product page), or it is included in the Motionary lifetime pass at $79 USD. Checkout is Stripe and you get an instant download of the full TypeScript source, including the SkSL shader and a demo screen. ## Related drops on Motionary - ChatGPT Image-Gen Dot Field ($5): https://motionary.dev/animations/chatgpt-image-gen-dot-field The closest sibling, another Skia-drawn field of dots, used as a loading placeholder rather than as a slider track. - ChatGPT Slider Model Picker ($10): https://motionary.dev/animations/chatgpt-slider-model-picker The same "pick a model quality" interaction as a chat composer slider, if you want the control in context instead of standalone. - World Clock Slider (Free): https://motionary.dev/animations/world-clock-slider A free Reanimated and Gesture Handler slider, a good place to see the shared value plus pan gesture pattern before buying. - Scrubbable Chart ($6): https://motionary.dev/animations/scrubbable-chart Another Skia canvas driven by a Gesture Handler pan, scrubbing a bar chart instead of a track. - LED Slide Button ($4): https://motionary.dev/animations/led-slide-button A slide-to-confirm control with the same drag-to-the-end payoff, built on Reanimated alone if you want the interaction without a shader. ## 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/dot-wave-slider/llms.txt Describes: https://motionary.dev/animations/dot-wave-slider Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01