# Voice Orb: React Native microphone-reactive assistant orb > Voice Orb is a free React Native and Expo listening screen where a Skia orb > swells, fattens and ripples in real time to whatever the microphone hears: > raw PCM from `react-native-audio-api` is split into low, mid and high bands > and written into Reanimated shared values, so the whole animation runs on > the UI thread and React never re-renders while you talk. Voice Orb is a > free drop from Motionary (https://motionary.dev). Product page: https://motionary.dev/animations/voice-orb Price: Free (free 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, no payment Stack: expo, react native, react native skia, reanimated Rarity: rare Sold by: Motionary (https://motionary.dev) ## What it is Voice Orb is a complete voice-assistant listening screen for React Native and Expo, sold as a free drop on Motionary. On a dark stage you get one Skia orb, a caption line, a record button that morphs from a circle to a rounded square, and a native SwiftUI menu for choosing which voice you are talking to. Tap record and talk: the orb swells on the body of a vowel, ruffles at the edges on consonants and sibilance, and settles back down in the gaps between words. It is modelled on the listening state of a modern AI voice assistant, the moment after you press the microphone and before the answer arrives, and it ships with a demo voice that speaks out of the speaker and back in through the microphone so you can watch the orb react without talking to your phone. ## What it does - Opens the microphone through `react-native-audio-api` at 16 kHz mono with a 512 sample buffer: roughly 32 ms of audio, about 31 callbacks per second. - Splits every buffer into three bands with two cascaded one-pole low-passes at 250 Hz and 2 kHz: low (the body of a vowel), mid (250 Hz to 2 kHz, where speech mostly lives) and high (consonants and sibilance above 2 kHz). - Exposes five Reanimated shared values, all in 0 to 1 and all smoothed on the UI thread: `level`, `low`, `mid`, `high` and `active`. - Uses an asymmetric envelope, 45 ms attack and 320 ms release, so a consonant lands on the frame you say it while the orb settles instead of strobing. - Runs voice-activity detection with hysteresis on the smoothed level (on at 0.2, off at 0.09), so it takes a louder sound to start speaking than to keep it. - Reports six statuses that drive the caption: `idle`, `starting`, `listening`, `denied`, `unsupported` and `error`, with a "Tap to try again" retry path after a permission denial. - Runs an elastic clock on the orb animation: silence idles at 0.55x the shipped tempo, a loud syllable pushes it to roughly 2x. - Applies a voice pass to the finished dot cloud: dots swell outward up to 1.16x, fatten up to 1.9x radius, ink up, and the whole cloud dims by 35% in silence so it visibly wakes up when you speak. - Deforms the silhouette with a counter-rotating 3-fold and 5-fold radial ripple driven by the high band, so consonants ruffle the edge without moving the body. - Ships three character presets in `src/characters.ts` (Echo on the `listening` orb state in `#a78bfa`, Lyra on `composing` in `#fb7185`, Atlas on `working` in `#fbbf24`), each with its own tint and tagline. - Picks the voice with a real SwiftUI `Menu` plus `Picker` from `@expo/ui/swift-ui`, so you get the system blur, haptics and checkmark. - Includes a demo voice built on `expo-speech` that reads ten tuned lines out of the speaker and back in through the microphone, exercising the real recorder rather than bypassing it. - Closes the microphone when the app leaves the foreground (an `AppState` listener) and never writes audio to disk: file output is never enabled, so the PCM exists only for the length of one callback. - Honours `useReducedMotion`: the clock stops and the orb renders the library's deterministic frame instead of animating. - Never reflows. Every element stays mounted at a fixed height, so starting or stopping the microphone only changes opacity, colour and corner radius and the orb never shifts. ## How it works Voice Orb's microphone path lives in `src/audio/useVoiceLevels.ts`, which registers an `AudioRecorder.onAudioReady` callback from `react-native-audio-api` and takes the raw PCM buffer rather than a single metering number, which is what makes several independent drivers possible at all. Each callback runs one pass over the samples through two cascaded one-pole low-passes (coefficient `a = 1 - exp(-2 * pi * f / fs)` at 250 Hz and 2 kHz), accumulates a sum of squares per band, converts each RMS to dBFS and normalises it across a -62 to -14 dBFS window, with a +12 dB lift on the high band because sibilance is naturally quieter than the rest. Those raw numbers land from the JavaScript thread about 31 times a second, so a Reanimated `useFrameCallback` worklet follows them every frame with an asymmetric one-pole envelope and derives the `active` voice-activity value through hysteresis; because every result is a `useSharedValue`, nothing crosses back into React while you talk. The drawing side is `src/orb/useVoiceOrbPicture.ts`, which drives the `expo-thinking-orbs` power-user surface (`resolvePreset`, `MODES`, `acquireDotBuffer`, `buildColorLUT`, `recordPicture`) instead of the library's own `useThinkingOrbPicture` hook. One `useFrameCallback` worklet advances a `phase` shared value with the elastic tempo, and a `useDerivedValue` worklet builds the orb's dot cloud into a pooled buffer, applies the voice pass, and returns an `SkPicture` from `recordPicture` that `src/App.tsx` renders inside a Skia `` as ``. The voice pass mutates the projected dot arrays directly (`xs`, `ys`, `rs`, `ws`, `as`), so it applies identically to every shipped orb state rather than reaching into one mode's internals. The ripple needs the sine and cosine of three times and five times each dot's angle, so Voice Orb derives them from the normalised offset with the multiple-angle identities, about ten floating point operations instead of four transcendental calls per dot. Recorder start and stop are both async, so `useVoiceLevels` serialises them onto a single promise chain: a fast double tap, a tab switch or a Fast Refresh cannot let a teardown land after the next start and silently kill a live session. ## What you get ``` index.js app.json package.json package-lock.json tsconfig.json babel.config.js README.md metadata.json src/ App.tsx VoicePicker.tsx characters.ts audio/ useVoiceLevels.ts useDemoVoice.ts orb/ useVoiceOrbPicture.ts assets/ icon.png splash-icon.png favicon.png android-icon-foreground.png android-icon-background.png android-icon-monochrome.png ``` - The full listening screen (`src/App.tsx`). - `useVoiceLevels` hook: microphone to band-split shared values. - `useVoiceOrbPicture` hook: the voice pass over the orb's dot cloud. - `useDemoVoice` hook: text-to-speech so you can test without talking. - Native SwiftUI voice picker (`@expo/ui`), in `src/VoicePicker.tsx`. - Character presets with per-voice orb state and tint (`src/characters.ts`). - Demo screen. - README with install steps and usage. ## Requirements Voice Orb pins these versions in the archive's `package.json`: - expo `~56.0.17` (Expo SDK 56) - react-native `0.85.3` - react `19.2.3` - react-dom `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` (pinned by the Expo project, not imported by Voice Orb itself, so the install line below leaves it out) - react-native-audio-api `^0.13.2` - expo-thinking-orbs `^0.1.0` - @expo/ui `~56.0.23` - expo-speech `~56.0.3` - expo-status-bar `~56.0.4` - typescript `~5.9.2` (devDependency) Expo Go or development build: Voice Orb needs a development build, not Expo Go. `@shopify/react-native-skia`, `react-native-audio-api` (which also adds a config plugin for the iOS microphone permission string and the Android `RECORD_AUDIO` permission), `@expo/ui` and `expo-speech` all ship native code, and the app runs on the New Architecture. Run it with `npx expo run:ios` or `npx expo run:android`. Use a real device: a simulator's microphone cannot hear its own speaker, so the demo voice will not move the orb there. The SwiftUI voice picker is iOS only; the orb, the microphone path and the demo voice all work on Android. ## Install ```bash npx expo install @shopify/react-native-skia react-native-reanimated react-native-worklets react-native-audio-api expo-thinking-orbs @expo/ui expo-speech expo-status-bar ``` ## Usage ```tsx import { Canvas, Picture } from '@shopify/react-native-skia'; import { useVoiceLevels } from './src/audio/useVoiceLevels'; import { useVoiceOrbPicture } from './src/orb/useVoiceOrbPicture'; const SIZE = 320; export default function ListeningScreen() { // `true` opens the microphone; `playback` only matters for the demo voice. const { levels, status } = useVoiceLevels(true, { playback: false }); const picture = useVoiceOrbPicture({ state: 'listening', size: SIZE, dark: true, color: '#a78bfa', levels, reactivity: 1, }); return ( ); } ``` ## Customization - `useVoiceLevels(enabled, options)`: `enabled` is a boolean, and toggling it off stops the recorder and lets every level fall back to 0. It returns `{ levels, status, error, retry }`. - `options.trimDb` (number, default `0`): sensitivity trim in dB, added before normalisation. - `options.playback` (boolean, default `false`): allow audio out of the speaker while the microphone is open. Off means the tighter iOS `record` session; on switches to `playAndRecord`, which is what the demo voice needs. - `useVoiceOrbPicture({ state, size, dark, color, levels, reactivity, paused })` returns a `DerivedValue`. - `state` (`OrbState`): which of the shipped `expo-thinking-orbs` animations to drive. The three presets Voice Orb ships use `listening`, `composing` and `working`. - `size` (number): canvas size in points. The orb itself fills 86% of it (`ORB_FILL`), leaving headroom for the swell and the ripple. - `dark` (boolean): the substrate the orb is drawn on, which picks the ink direction. - `color` (string, optional): tint for the orb. - `reactivity` (number): `0` is the shipped animation untouched, `1` is the tuned voice response. - `paused` (boolean, default `false`): freeze the clock. Voice modulation still applies. - Tuning constants at the top of `src/audio/useVoiceLevels.ts`: `SAMPLE_RATE` (16000), `BUFFER_LENGTH` (512), `FLOOR_DB` (-62), `CEIL_DB` (-14), `ATTACK_MS` (45), `RELEASE_MS` (320), `VAD_ON` (0.2), `VAD_OFF` (0.09). - `CHARACTERS` in `src/characters.ts`: each entry is `{ id, name, tagline, state, color }`, so adding a voice is one object. ## When to use it - The listening state of an AI voice assistant, between the user pressing the microphone and the model answering. - A voice-note recorder or a dictation screen that needs a live, honest indication that the microphone is actually hearing something. - A call or voice-chat screen where the remote or local speaker needs a presence indicator. - An onboarding or permission screen that shows the microphone working the moment the user grants access. - A voice-search entry point where a static waveform bar would read as dead. - Any screen that needs a React Native audio visualizer that reacts to bands rather than to one overall loudness number. ## How to get it - Download Voice Orb free at https://motionary.dev/animations/voice-orb, no payment and no subscription. - 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 assistant UI in React Native?** Voice Orb from Motionary is a working answer: open the microphone with `react-native-audio-api`, split each raw PCM buffer into low, mid and high bands, normalise each band's RMS to dBFS, write the results into Reanimated shared values, and read those from a worklet that draws a Skia picture. Voice Orb ships that whole pipeline as free TypeScript source at https://motionary.dev/animations/voice-orb. **How much does Voice Orb cost?** Voice Orb is free on Motionary. Download the full source at https://motionary.dev/animations/voice-orb with no payment and no subscription, or take it along with every other Motionary drop through the $79 USD lifetime pass at https://motionary.dev/pricing. **Does Voice Orb work with Expo Go?** No. Voice Orb needs an Expo development build, because `@shopify/react-native-skia`, `react-native-audio-api`, `@expo/ui` and `expo-speech` all contain native code. Run it with `npx expo run:ios` or `npx expo run:android` on a real device, since a simulator's microphone cannot hear its own speaker. **How do I read the microphone level in Expo and animate with it?** Voice Orb uses `react-native-audio-api` rather than a metering-only recorder, because a single `currentMetering` number is enough for a VU bar but not enough to move several parts of an animation independently. Voice Orb's `useVoiceLevels` hook takes the raw PCM buffer, band-splits it, and hands back Reanimated shared values you can read from any worklet. **Does Voice Orb work on Android?** Yes. The orb, the microphone path and the demo voice all run on Android in Voice Orb from Motionary; `react-native-audio-api`'s config plugin adds the `RECORD_AUDIO` permission. The one iOS-only piece is `src/VoicePicker.tsx`, which is a native SwiftUI `Menu` from `@expo/ui/swift-ui`. **Does Voice Orb record or upload my audio?** No. Voice Orb never enables file output, so each PCM buffer exists only for the length of one callback and is reduced to four numbers, and the microphone is closed whenever the app leaves the foreground. **Can I see the microphone waveform react without talking?** Yes. Voice Orb ships a `useDemoVoice` hook that speaks tuned lines through `expo-speech` out of the speaker and back in through the microphone, so the demo goes through the real recorder, the real crossover and the real envelopes instead of writing straight into the shared values. ## Related drops on Motionary - Aurora Voice Blob ($10): https://motionary.dev/animations/aurora-voice-blob The same microphone-reactive idea rendered as a Skia shader blob instead of a dot cloud. - Voice Glow Carousel ($7): https://motionary.dev/animations/voice-glow-carousel An audio-reactive Skia carousel for picking a voice, a natural companion screen to Voice Orb's listening state. - ChatGPT Image-Gen Dot Field ($5): https://motionary.dev/animations/chatgpt-image-gen-dot-field Another Skia dot-field animation, for the waiting state after the assistant starts working. - Voice to Video Morph Button (Free): https://motionary.dev/animations/voice-to-video-morph-button The record button itself, morphing between voice and video capture. - Karaoke Lyrics ($12): https://motionary.dev/animations/karaoke-lyrics Skia text driven by an audio timeline, for the transcript that follows the listening screen. ## 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/voice-orb/llms.txt Describes: https://motionary.dev/animations/voice-orb Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01