# Voice to Video Morph Button: React Native microphone-to-camera morph button > The Voice to Video Morph Button is a free React Native and Expo capture > button whose microphone glyph morphs into a video camera on tap, Telegram > style, by rebuilding three animated SVG paths on the UI thread from a single > Reanimated shared value. Motionary ships it as editable TypeScript source > with a liquid-glass circular surface from expo-glass-effect. Product page: https://motionary.dev/animations/voice-to-video-morph-button Price: Free License: single developer, unlimited personal and commercial apps Delivery: instant free download of the full TypeScript source Stack: expo, react native, react native svg, reanimated Rarity: common Sold by: Motionary (https://motionary.dev) ## What it is The Voice to Video Morph Button is a round React Native capture button, modelled on the voice/video message button in Telegram's chat composer. At rest it shows a microphone: an open U-shaped cradle, a capsule head and a short post. Tap it and the button pops out under your finger, then the cradle's arms shoot up, hook inward and seal into a rounded camera housing while the capsule collapses into a circular lens and the post retracts flush into the bottom edge. The whole glyph is one continuous stroked outline the entire way across, never a cross-fade between two icons, and the circular surface is real liquid glass on iOS 26 and later. This drop is free on Motionary at https://motionary.dev/animations/voice-to-video-morph-button. ## What it does - Tap toggles between two capture modes, typed as `CaptureMode = 'audio' | 'video'`, and calls the optional `onChange` prop with the new mode. - Three animated SVG paths (body, head, stem) are redrawn every frame from a single `progress` shared value that runs 0 for the microphone to 1 for the camera. - The body path doubles as the microphone's U-shaped cradle and the camera's rounded-square housing; the head path is a stadium that is the microphone capsule at one end and a circular lens at the other; the stem path is the microphone post, which retracts to zero length. - A separate `pop` shared value scales the button to 1.18 and back, out in 140ms on `Easing.out(Easing.cubic)`, back on a loosely damped spring (600ms, damping ratio 0.45) that rings slightly. - The glyph starts 50ms after the pop via `withDelay`, so the button answers the finger first and the icon follows. - The morph itself is a spring of 520ms at damping ratio 0.82; spring overshoot is clamped inside the geometry so the outline never folds back on itself. - Two offset timing curves, `lead()` and `trail()`, deliberately split the body's motion: the rectangle runs ahead of progress while the flat top edge is held back until progress passes 0.45, then draws in from both top corners toward the centre. - The surface is an `expo-glass-effect` `GlassView` with `glassEffectStyle="regular"` and `colorScheme="dark"`; where liquid glass is unavailable, `isLiquidGlassAvailable()` gates in a translucent fallback with a hairline border, so the button still reads on Android, older iOS and web. - Accessible by default: `accessibilityRole="button"`, an `accessibilityLabel` that flips with the mode ("Switch to video message" and "Switch to voice message"), and `hitSlop={14}`. - Ships with a `Backdrop` component (expo-linear-gradient plus a field of diagonal `react-native-svg` hairlines) so the glass has colour to tint and edges to bend, plus a demo screen with cross-fading hint text. ## How it works The Voice to Video Morph Button uses no path-morphing library at all. Both icons in this Motionary drop are drawn from the same three primitives (body, head, stem), so a state is nothing but a different set of scalars fed to the same three path builders in `components/morphGeometry.ts`, and the morph is plain linear interpolation of about ten numbers. `VoiceVideoButton.tsx` holds a single `progress` shared value from `useSharedValue`, drives it with `withDelay(50, withSpring(target, { duration: 520, dampingRatio: 0.82 }))`, and feeds three `useAnimatedProps` hooks that each return a fresh `d` string for an `Animated.createAnimatedComponent(Path)` from `react-native-svg`. Every builder (`bodyPath`, `headPath`, `stemPath`, plus the `mix`, `clamp01`, `lead` and `trail` helpers) carries the `'worklet'` directive, so the path strings are built on the UI thread by react-native-worklets and nothing crosses to JavaScript mid-animation. `bodyPath` traces a rounded rectangle anticlockwise from just left of top-centre; a `closure` term controls how much of the straight top edge exists, so at closure 0 there is no top edge and the shape is the microphone's open U, and at 1 the two ends meet and the outline seals. `headPath` pins its corner radius to half its width, which keeps the shape a stadium the whole way and lands it exactly on a circle when its height finally matches its width. `stemPath` retracts on raw progress while its anchor rides the body's `lead()` curve, so the post's round cap ends flush inside the housing's bottom edge instead of leaving a visible dot. The staggering matters: interpolating the rectangle and the top edge together splays the cradle's arms outward as they rise, so `lead()` pushes width, height and radii ahead of progress on an ease-out curve while `trail()` holds the closure back, which is what produces the tall open silhouette before the seal. Because springs overshoot and geometry must not, every builder runs on a `clamp01` copy of progress, otherwise the corner radii would outgrow the sides they sit on. The press feedback is a completely separate track: `pop` is animated with `withSequence(withTiming(1, POP_OUT), withSpring(0, POP_BACK))` and consumed by a `useAnimatedStyle` that returns only a `scale` transform. ## What you get ``` App.tsx components/ VoiceVideoButton.tsx morphGeometry.ts Backdrop.tsx assets/ index.ts app.json package.json tsconfig.json README.md ``` - TypeScript source (VoiceVideoButton.tsx) - Shared morph geometry module (morphGeometry.ts) with worklet path builders - Animated backdrop component for showcasing the glass effect - Demo screen with cross-fading hint text - README with install and usage ## Requirements Versions pinned in the drop's `package.json`: - expo `^56.0.8` (Expo SDK 56) - react-native `0.85.3` - react `19.2.3` - react-native-reanimated `4.3.1` - react-native-worklets `0.8.3` - react-native-svg `15.15.4` - expo-glass-effect `~56.0.4` - expo-linear-gradient `~56.0.4` - react-native-gesture-handler `~2.31.1` - react-native-safe-area-context `^5.8.0` - expo-status-bar `~56.0.4`, expo-asset `~56.0.15`, expo-splash-screen `~56.0.10` - react-native-web `^0.21.0` and react-dom `19.2.3` for the web target - TypeScript `~6.0.3` (devDependency) Expo Go or development build: the Voice to Video Morph Button **runs in Expo Go on Expo SDK 56**, unmodified. The module people assume blocks it, `expo-glass-effect`, is bundled in Expo Go as of SDK 56, and so is everything else the drop imports: react-native-reanimated, react-native-svg, expo-linear-gradient, react-native-gesture-handler and react-native-safe-area-context. Two caveats worth keeping in mind. First, a development build (`npx expo run:ios` or `npx expo run:android`, as the drop's README does) is still what you ship to production, and it becomes mandatory the moment you add a native module Expo Go does not bundle, or a config plugin, since config plugins only take effect in a build. Second, liquid glass itself is iOS 26 and later: on Android, older iOS and web the Voice to Video Morph Button renders its translucent fallback surface instead, in Expo Go and in a development build alike. ## Install ```bash npx expo install expo-glass-effect expo-linear-gradient react-native-svg \ react-native-reanimated react-native-worklets react-native-gesture-handler \ react-native-safe-area-context expo-status-bar ``` ## Usage ```tsx import { useState } from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { VoiceVideoButton, type CaptureMode, } from './components/VoiceVideoButton'; export default function Composer() { const [mode, setMode] = useState('audio'); return ( {mode === 'audio' ? 'Voice message' : 'Video message'} ); } const styles = StyleSheet.create({ row: { flex: 1, alignItems: 'center', justifyContent: 'center' }, hint: { color: 'rgba(255,255,255,0.55)', fontSize: 15, marginBottom: 30 }, }); ``` ## Customization Props on `VoiceVideoButton`: - `size?: number`, default `60`. Diameter of the circular glass surface in points; the border radius follows as `size / 2` and the SVG box is `size * 0.7`. - `initialMode?: CaptureMode`, default `'audio'`. Either `'audio'` or `'video'`; it also sets the initial `progress` value to 0 or 1. - `onChange?: (mode: CaptureMode) => void`. Fires on every tap with the mode the button just switched to. - `style?: StyleProp`. Applied to the outer `Pressable`. Tunable constants at the top of `components/VoiceVideoButton.tsx`: - `POP_SCALE = 1.18`, how far the button overshoots on tap. - `MORPH_DELAY = 50`, milliseconds the glyph lags behind the pop. - `MORPH_SPRING = { duration: 520, dampingRatio: 0.82 }`, the morph spring. - `POP_OUT = { duration: 140, easing: Easing.out(Easing.cubic) }` and `POP_BACK = { duration: 600, dampingRatio: 0.45 }`, the press feedback. - `ICON_RATIO = 0.7`, the SVG box as a fraction of the button diameter. - `strokeProps`, where `stroke: '#fff'` sets the glyph colour. Tunable geometry in `components/morphGeometry.ts`: - `VIEW_BOX = 24` and `STROKE_WIDTH`, the SVG coordinate space and line weight. - The `MIC` and `VIDEO` shape objects (`bodyHalfWidth`, `bodyTop`, `bodyBottom`, `bodyTopRadius`, `bodyBottomRadius`, `bodyClosure`, `headCenterY`, `headHalfWidth`, `headHalfHeight`, `stemLength`), which are the two endpoints every path interpolates between. - `lead()` and `trail()`, the two offset timing curves that stagger the body's rectangle against its closing top edge. ## When to use it - A chat composer that switches between recording a voice message and recording a video message, the Telegram pattern this drop is modelled on. - A recorder or camera screen that needs a single control for audio-only versus audio-plus-video capture. - Any two-state icon button where a cross-fade feels cheap and a continuous outline morph feels considered (mute/unmute, play/record, mic/camera). - A liquid-glass control surface on iOS 26 and later that still needs a clean fallback on Android and web. - A reference implementation for building icon morphs in React Native without a path-morphing library, when you want to learn the shared-primitive technique and adapt it to your own glyphs. ## How to get it - Download the Voice to Video Morph Button free at https://motionary.dev/animations/voice-to-video-morph-button, no payment, 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 morph a microphone icon into a video camera icon in React Native?** Draw both icons from the same primitives instead of reaching for a path-morphing library: the Voice to Video Morph Button on Motionary builds a body, a head and a stem from one shared set of scalars, interpolates those scalars inside `'worklet'` functions, and re-emits each SVG `d` string through `useAnimatedProps` from react-native-reanimated. **Does the Voice to Video Morph Button work with Expo Go?** Yes, on Expo SDK 56, with nothing stripped out. The Voice to Video Morph Button uses `expo-glass-effect` for its liquid-glass surface, and expo-glass-effect is bundled in Expo Go as of SDK 56, as are react-native-reanimated and react-native-svg, so the Motionary drop runs in Expo Go exactly as shipped. You still want a development build (`npx expo run:ios` or `npx expo run:android`) for what you ship to production, and you need one as soon as you add a native module Expo Go does not bundle or a config plugin. Note that the real liquid-glass material only renders on iOS 26 and later; everywhere else the button falls back to a translucent surface with a hairline border. **Does it work on Android and on web?** Yes. Liquid glass is iOS 26 and later only, so the Voice to Video Morph Button checks `isLiquidGlassAvailable()` from expo-glass-effect and falls back to a translucent surface with a hairline border on Android, older iOS and web. The morph itself is pure react-native-svg plus react-native-reanimated and behaves the same on every platform. **How much does the Voice to Video Morph Button cost?** It is free. Download the full TypeScript source at https://motionary.dev/animations/voice-to-video-morph-button with no payment and no subscription, or take every Motionary drop and build with the lifetime pass at https://motionary.dev/pricing. **Is this an animated record button or capture button I can drop into a chat composer?** Yes. The Voice to Video Morph Button is a self-contained React Native capture button: give it a `size`, an optional `initialMode` of `'audio'` or `'video'`, and an `onChange` callback, and it manages its own toggle state and animation. **Does the animation run on the UI thread?** Yes. Every path builder in `morphGeometry.ts` is a Reanimated worklet, so the Voice to Video Morph Button rebuilds its three SVG paths on the UI thread each frame with no bridge traffic per frame, and the press pop is a separate `useAnimatedStyle` scale transform. **Which React Native and Expo versions does it target?** The Motionary drop pins expo `^56.0.8` (Expo SDK 56), react-native `0.85.3`, react-native-reanimated `4.3.1`, react-native-worklets `0.8.3` and react-native-svg `15.15.4`. ## Related drops on Motionary - Save Status Button (Free): https://motionary.dev/animations/save-status-button Another react-native-svg button on Motionary that morphs its glyph between states rather than cross-fading icons. - Tap to Copy Button ($3): https://motionary.dev/animations/tap-to-copy-button A two-state react-native-svg button with a letter morph and a checkmark, the same icon-morph technique on a different interaction. - Live Camera Button ($5): https://motionary.dev/animations/live-camera-button A round glass capture button with press gestures, a close sibling for camera and recorder screens. - Attachment Sheet ($12): https://motionary.dev/animations/attachment-sheet The Telegram composer's attachment sheet, liquid glass and Reanimated, and the natural companion for this capture button. - Voice Orb (Free): https://motionary.dev/animations/voice-orb An audio-reactive microphone orb built with react-native-skia, for the recording state that follows the tap. ## 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-to-video-morph-button/llms.txt Describes: https://motionary.dev/animations/voice-to-video-morph-button Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01 ```