# Aurora Voice Blob: React Native voice-reactive audio visualizer > Aurora Voice Blob is a React Native and Expo audio visualizer: a soft blue > aurora that breathes up from the bottom of the screen and swells with your > voice, drawn as a single SkSL fragment shader in > @shopify/react-native-skia and driven by live microphone loudness smoothed > on the UI thread with react-native-reanimated. It is sold as editable > TypeScript source by Motionary (https://motionary.dev). Product page: https://motionary.dev/animations/aurora-voice-blob 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 Rarity: legendary Sold by: Motionary (https://motionary.dev) ## What it is Aurora Voice Blob is a full-screen listening background for React Native and Expo apps. On a warm off-white page (#F6F6F4) a hazy blue cloud sits along the bottom edge, breathing gently while nothing is happening. The moment you speak, the cloud lifts: it grows taller, its rim gets more turbulent, and the blue deepens from a pale haze (#B4CDE6) toward a saturated bottom (#588DC8). Go quiet and it drains back down. Nothing in the animation is driven by a touch gesture: the input is your voice, captured from the device microphone, and the on-screen buttons only start, pause and stop the recorder. The shape is deliberately cloud-like rather than wave-like, so it reads as an aurora or a cumulus lobe instead of the sine-wave waterline most audio visualizers produce. It is the kind of listening state you see behind a modern voice assistant screen. ## What it does - Renders the entire visual as one SkSL fragment shader on a Skia `Canvas` `Fill`, so there is a single draw call and no per-frame React re-render. - Maps live microphone loudness to a 0..1 `level` and drives the blob's height, edge turbulence, rim softness and color saturation from it. - Smooths that level with a fast-attack, slow-release curve: 100ms rising, 450ms falling, so the swell snaps up with speech and drains on silence. - Calibrates the dB window to human speech: a floor of -50 dB and a ceiling of -14 dB, set a touch above conversational speech (around -25 dB), with a `pow(t, 1.4)` curve so conversation lifts the blob well without pinning it at maximum. - Shapes the top edge with 4-octave fractal Brownian motion (fbm) noise folded into rounded lobes with creased valleys, plus two counter-drifting layers so the cloud reshapes instead of merely bobbing. - Adds two more fbm density layers inside the body (one broad, one wispy) and a depth term that saturates the blue toward the bottom of the screen. - Breathes at rest: a slow `sin(u_time * 0.7)` term keeps the shoreline alive even in silence. - Ships mic controls: a settings button, a mic toggle that swaps between the `mic` and `mic-off` Ionicons, and a dark close button that fully stops the recorder, each with `expo-haptics` feedback. - Keeps toggling instant by pausing and resuming the recorder rather than tearing it down, so the iOS audio session stays warm. - Serializes every native recorder call through a promise chain so a stop can never overlap an in-flight start. - Requests `RECORD_AUDIO` at runtime on Android and declares `NSMicrophoneUsageDescription` for iOS. ## How it works Aurora Voice Blob splits into two files: `components/VoiceBlob.tsx` draws, and `components/Container.tsx` listens. In `VoiceBlob.tsx` the shader source is compiled once at module scope with `Skia.RuntimeEffect.Make(SHADER_SOURCE)` and painted through `` from @shopify/react-native-skia, with the Canvas set to `StyleSheet.absoluteFill` and `pointerEvents="none"` so it never eats touches. Uniforms are packed by a Reanimated `useDerivedValue` that reads Skia's `useClock()` shared value for `u_time`, the screen size from `useWindowDimensions` for `u_resolution`, and the mic `level` shared value for `u_level`; because that derived value is a worklet, the uniform update runs on the UI thread every frame and React never re-renders while the blob animates. Inside the SkSL `main(vec2 xy)`, the fragment position is normalized to uv, flipped to `yUp`, and a shoreline height `h = 0.12 + u_maxRise * u_level + breathe` is displaced by two `fbm` samples: `lobes = 1.0 - abs(n1 - 0.5) * 2.0` gives rounded cumulus bumps, and a `smoothstep` across a volume-widened falloff band (`soft = 0.11 + 0.09 * u_level`) produces the vaporous rim; two further `fbm` layers modulate interior density and a `pow`ed depth term mixes the pale edge blue into the deep blue. On the audio side, `Container.tsx` calls `Sound.setSubscriptionDuration(0.05)` and `Sound.addRecordBackListener` from react-native-nitro-sound to receive a metering callback roughly every 50ms; `dbToLevel` clamps `e.currentMetering` into the [-50, -14] window, normalizes it and applies `Math.pow(t, 1.4)`, then writes the result into a `useSharedValue` with `withTiming` whose duration flips between 100ms and 450ms depending on whether the value is rising or falling (`Easing.out(Easing.quad)`). Recorder lifecycle is the fiddly part: native `startRecorder` and `stopRecorder` stay pending for hundreds of milliseconds while the iOS audio session activates, so every call goes through a `runExclusive` serial promise chain, and the mic toggle uses `pauseRecorder` and `resumeRecorder` (with a `startedRef` guard) so only the close button pays for a full teardown. ## What you get ``` App.tsx index.ts components/ Container.tsx VoiceBlob.tsx assets/ icon.png adaptive-icon.png splash-icon.png app.json babel.config.js package.json tsconfig.json README.md ``` - Skia shader component (VoiceBlob.tsx) - Mic capture + level container (Container.tsx) - SkSL fragment shader with FBM noise - Reanimated shared-value level smoothing - Haptic mic toggle controls - README with install + usage - MP4 preview ## Requirements Aurora Voice Blob ships as a runnable Expo app; these are the exact versions pinned 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 - @shopify/react-native-skia 2.6.2 - react-native-nitro-sound ^0.2.15 - react-native-nitro-modules ^0.35.9 - react-native-gesture-handler ~2.31.1 - react-native-safe-area-context ~5.7.0 - expo-haptics ~56.0.3 - expo-status-bar ~56.0.4 - expo-font ~56.0.5 - expo-asset ~56.0.14 - @expo/vector-icons ^15.0.3 - typescript ~6.0.3 (devDependency) Aurora Voice Blob needs a development build, not Expo Go: both @shopify/react-native-skia and react-native-nitro-sound (through react-native-nitro-modules) are native modules that are not part of the Expo Go runtime. Run it with `npx expo run:ios` or `npx expo run:android`, or build a custom development client. It also needs microphone permission: `NSMicrophoneUsageDescription` on iOS and `android.permission.RECORD_AUDIO` on Android, both already declared in the included `app.json`. ## Install ```bash npx expo install @shopify/react-native-skia react-native-reanimated react-native-worklets react-native-gesture-handler react-native-safe-area-context react-native-nitro-sound react-native-nitro-modules expo-haptics expo-status-bar @expo/vector-icons ``` ## Usage ```tsx import { useEffect } from 'react'; import { Easing, useSharedValue, withTiming } from 'react-native-reanimated'; import Sound from 'react-native-nitro-sound'; import { VoiceBlob } from './components/VoiceBlob'; export default function ListeningScreen() { const level = useSharedValue(0); // 0 = silence, 1 = loud useEffect(() => { Sound.setSubscriptionDuration(0.05); // metering every 50ms Sound.addRecordBackListener((e) => { const db = Math.min(Math.max(e.currentMetering ?? -50, -50), -14); const next = Math.pow((db + 50) / 36, 1.4); // 0..1, speech-calibrated level.value = withTiming(next, { duration: next > level.value ? 100 : 450, // fast attack, slow release easing: Easing.out(Easing.quad), }); }); Sound.startRecorder(undefined, undefined, true); return () => { Sound.removeRecordBackListener(); Sound.stopRecorder().catch(() => {}); }; }, []); return ; } ``` The Skia `Canvas` inside `VoiceBlob` uses `StyleSheet.absoluteFill`, so mount `VoiceBlob` inside a container that has a size (a `flex: 1` View, or a router screen) and it fills the screen behind your own UI. ## Customization - `level` (required, `SharedValue`): smoothed microphone loudness, 0 for silence to 1 for loud. Any source works, not just a microphone. - `maxRise` (optional, `number`, default `0.16`): how far the blob rises above its resting shoreline at full loudness, as a fraction of screen height. The resting height is about `0.12`, so the top peaks around `0.12 + maxRise`. - `MIN_DB` / `MAX_DB` in `Container.tsx` (default `-50` and `-14`): the dB window mapped to 0..1. Raise `MAX_DB` for a less sensitive blob. - The `Math.pow(t, 1.4)` response curve in `dbToLevel`: lower the exponent for a more reactive blob, raise it to demand louder speech. - The `withTiming` durations in `Container.tsx` (default 100ms attack, 450ms release) control how sharply the swell rises and how slowly it drains. - `Sound.setSubscriptionDuration(0.05)` sets the metering interval in seconds. - The `BG`, `SOFT` and `DEEP` constants at the top of the SkSL source in `VoiceBlob.tsx` (default `#F6F6F4`, `#B4CDE6`, `#588DC8`) set the page, hazy rim and saturated bottom colors. - Shader constants inside `VoiceBlob.tsx`: the `soft` falloff band (`0.11 + 0.09 * u_level`) for rim softness, the fbm loop count (4 octaves) for noise detail, and the `0.012 * sin(u_time * 0.7)` idle breathing term. ## When to use it - The listening state of a voice assistant or AI chat app, behind a "Start talking" prompt. - A voice recorder or voice memo screen that needs live feedback that the mic is actually picking the user up. - Voice note capture inside a chat composer, as a full-screen takeover while the user holds or toggles the mic. - Speech-to-text or dictation input, where the swell tells the user their volume is high enough to transcribe. - A hands-free or in-car mode where an ambient, glanceable audio visualizer beats a waveform readout. - Onboarding steps that ask the user to grant microphone permission and then say something out loud. ## How to get it - Buy Aurora Voice Blob on its own at https://motionary.dev/animations/aurora-voice-blob, $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 voice reactive audio visualizer in React Native?** Capture microphone metering (dB) from a native recorder, map it to a 0..1 value, smooth it into a Reanimated shared value with a fast-attack, slow-release `withTiming`, and feed that shared value into a Skia shader or animated style as a uniform. Aurora Voice Blob from Motionary is a working implementation of exactly that pipeline in React Native and Expo, using react-native-nitro-sound for metering and one SkSL fragment shader for the visual. **Does Aurora Voice Blob work with Expo Go?** No. Aurora Voice Blob needs an Expo development build because @shopify/react-native-skia and react-native-nitro-sound are native modules that Expo Go does not bundle. Run `npx expo run:ios` or `npx expo run:android`, or install a custom development client, and the drop from Motionary works as shipped. **How do I read microphone loudness (dB) in an Expo app?** Aurora Voice Blob uses react-native-nitro-sound: it calls `Sound.setSubscriptionDuration(0.05)` for a 50ms interval and `Sound.addRecordBackListener`, which reports `currentMetering` in decibels (averagePower on iOS, an amplitude-derived dB on Android). The Motionary drop clamps that into a calibrated [-50, -14] window and curves it into a 0..1 level. **Does Aurora Voice Blob run on Android as well as iOS?** Yes. Aurora Voice Blob from Motionary ships microphone handling for both platforms: it requests `PermissionsAndroid.PERMISSIONS.RECORD_AUDIO` at runtime on Android and declares `NSMicrophoneUsageDescription` on iOS, and its dB window is calibrated for both iOS averagePower and Android amplitude-derived metering. **Will the animation drop frames while my app is busy?** No, the animation of Aurora Voice Blob lives on the UI thread. The Skia uniforms are packed in a Reanimated `useDerivedValue` worklet driven by `useClock()`, so React does not re-render per frame; only the microphone callback and the mic toggle touch the JavaScript thread. **Can I drive the blob from something other than a microphone?** Yes. The `VoiceBlob` component of Aurora Voice Blob only takes a `level: SharedValue` (0 to 1) and an optional `maxRise`, so you can feed it playback amplitude, a speech-to-text confidence value, a slider or a scripted animation instead of live mic input. **How much does Aurora Voice Blob cost and what do I actually receive?** Aurora Voice Blob is $10 USD on Motionary at https://motionary.dev/animations/aurora-voice-blob (price as of 2026-09-01, live price on the product page), or it is included in the Motionary lifetime pass at $79 USD. You receive the complete editable TypeScript source (`VoiceBlob.tsx`, `Container.tsx`, the SkSL shader and a runnable Expo app), delivered as an instant download after Stripe checkout. ## Related drops on Motionary - Voice Orb (Free): https://motionary.dev/animations/voice-orb The same audio-reactive idea as a compact Skia orb instead of a full-screen aurora, and free to download. - Voice Glow Carousel ($7): https://motionary.dev/animations/voice-glow-carousel Another audio-reactive Skia shader drop, this one pairing the glow with a snap-paging voice picker and settings sheet. - Pool Water Shader ($12): https://motionary.dev/animations/pool-water-shader A full-screen SkSL background shader with animated caustics, if you want an ambient backdrop that is not driven by the microphone. - Halo Button ($5): https://motionary.dev/animations/halo-button Takes the same aurora glow language down to a single button, built with a Skia shader. - Glass Magnifier ($10): https://motionary.dev/animations/glass-magnifier Another `RuntimeEffect` SkSL drop, useful as a second worked example of passing Reanimated shared values into Skia uniforms. ## 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/aurora-voice-blob/llms.txt Describes: https://motionary.dev/animations/aurora-voice-blob Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01 ```