# Live Camera Button: React Native glass button with a live camera fill
> Live Camera Button is a React Native and Expo component from Motionary: a
> pill-shaped pressable whose surface is a live front-facing `expo-camera`
> preview, softened by an `expo-blur` BlurView, with a single Reanimated shared
> value driving the shadow collapse, the inverting inset highlights and the
> label scale on every press.
Product page: https://motionary.dev/animations/live-camera-button
Price: $5 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, expo blur, react native
Rarity: rare
Sold by: Motionary (https://motionary.dev)
## What it is
Live Camera Button is a React Native and Expo button whose fill is not a color
or an image but the phone's own front camera, streaming in real time behind a
frosted glass overlay. At rest the pill reads as a piece of milky glass sitting
slightly proud of the screen: a soft drop shadow underneath, two asymmetric side
shadows, and three stacked white inset highlights that give it a lit rim. Press
it and the whole thing sinks. The drop shadow flattens to nothing, the white
highlights cross-fade out and a single dark inset shadow fades in so the rim
inverts, and the "Button" label scales down slightly. Because the fill is a live
camera feed, whatever is in front of the phone keeps moving inside the button,
which is what makes it read as a lens rather than as a texture. The Live Camera
Button drop from Motionary ships the whole thing as editable TypeScript.
## What it does
- Renders a live front-facing camera preview as the button's fill, using an
`expo-camera` `CameraView` with `facing="front"` and `zoom={CAMERA_ZOOM}`
(0.1), so the feed is pulled in slightly rather than showing a wide face shot.
- Layers an `expo-blur` `BlurView` at `intensity={20}` over the camera feed, so
the image is legible as motion and light but never as a recognisable picture.
- Drives the entire press animation from one Reanimated shared value,
`progress`, tweened between 0 and 1 with `withTiming` over 120ms
(`PRESS_DURATION`) on `onPressIn` and `onPressOut`.
- Collapses an outer drop shadow from a 4px offset and 4px blur to 0px, and
closes two asymmetric side shadows (one offset -4px, one +4px, each with a 6px
blur) as the button is pressed.
- Cross-fades four absolutely positioned inset-shadow layers: three white idle
highlights (`inset 0 0px 3px`, `inset 0 2px 5px`, `inset 0 4px 6px`) fade out
while one deep dark layer (`inset 0 4px 10px 2px #0000007b`) fades in.
- Scales the label from 1 to 0.95 in the same tween, so the text compresses with
the surface instead of animating on its own timeline.
- Handles camera permission end to end with a `useCamera` hook exposing a
four-state machine (`loading`, `granted`, `denied`, `blocked`) plus `isReady`,
`isLoading`, `canRetry` and `requestPermission`.
- Ships a `PermissionState` fallback screen that renders a spinner while
checking, a "Camera Access Blocked" message when the user has blocked access
in Settings, and a "Grant Access" button while permission can still be asked.
- Auto-requests permission on mount by default, controlled by the hook's
`autoRequest` argument.
- Runs on both iOS and Android; the permission fallback screen uses `SymbolView`
from `expo-symbols` for its camera glyph.
## How it works
The technique behind Motionary's Live Camera Button is a nested view stack plus
one shared value, and it is worth copying whenever you want a press to feel
physical in React Native. In `components/Button.tsx`, the button itself is an
`AnimatedPressable` created with `Animated.createAnimatedComponent(Pressable)`,
centred inside a plain `View`, so a Reanimated style can be attached directly
to the touch target. A single `useSharedValue(0)` called `progress` is the only
piece of animation state: `onPressIn` sets it to
`withTiming(1, { duration: 120 })` and `onPressOut` sets it back to 0. Six
separate `useAnimatedStyle` worklets then `interpolate` against that same
value, which means every layer is computed in the same frame on the UI thread
with no re-render and no bridge traffic: `animatedDropShadow` drives the outer
`boxShadow` offset and blur, `animatedShadowLeft` and `animatedShadowRight`
drive the two side shadows on nested `Animated.View`s, `idleOpacity` and
`pressedOpacity` are exact inverses of each other so the white inset highlights
and the dark pressed rim cross-fade rather than pop, and `animatedLabelStyle`
interpolates a `scale` from 1 to 0.95. The shadows are written as React
Native's `boxShadow` style string built inside the worklet, so offset and blur
animate together rather than being faked with a second view. Depth comes from
stacking: an outer `Pressable` for the drop shadow, two nested `Animated.View`s
for the asymmetric side shadows, then a `buttonInner` view with
`overflow: 'hidden'` and an 80px border radius that clips everything to the
pill. Inside that, the `CameraView` sits at the bottom and the `BlurView` is
absolutely filled over it with `zIndex: 4`, with the four inset-shadow layers
and the label above the blur at `zIndex: 100`. Permission handling is
deliberately kept out of the animation path: `hooks/useCamera.ts` wraps Expo's
`useCameraPermissions` into a derived status, and `ButtonContainer`
early-returns `` while `isReady` is false, so the animated
tree only ever mounts once the camera can actually stream. The tunable numbers
(`CAMERA_ZOOM`, `BLUR_INTENSITY_PRIMARY`, `BLUR_INTENSITY_SECONDARY`) live in
`constants/camera.ts`.
## What you get
```
App.tsx
index.ts
app.json
package.json
package-lock.json
tsconfig.json
README.md
components/
Button.tsx
PermissionState.tsx
hooks/
useCamera.ts
constants/
camera.ts
index.ts
assets/
icon.png
adaptive-icon.png
splash-icon.png
```
- TypeScript source (`components/Button.tsx`)
- `useCamera` hook with permission handling
- `PermissionState` fallback component
- Camera zoom and constants module (`constants/camera.ts`)
- Demo `App.tsx` entry, plus `app.json` with the `expo-camera` plugin and its
permission strings already configured
- `README.md` with install and usage notes
## Requirements
Live Camera Button from Motionary is an Expo app template, and these are the
versions pinned in the shipped `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
react-native-gesture-handler: ~2.31.1
expo-camera: ~56.0.7
expo-blur: ~56.0.3
expo-symbols: ~56.0.5
expo-status-bar: ~56.0.4
expo-font: ~56.0.5
react-native-safe-area-context: ~5.7.0
```
The template's `package.json` also pins `@expo/metro-runtime` (~56.0.12),
`@expo/ui` (~56.0.13), `@expo/vector-icons` (^15.0.3),
`@react-native-masked-view/masked-view` (^0.3.2), `expo-glass-effect`
(~56.0.4), `expo-linear-gradient` (~56.0.4), `expo-sensors` (~56.0.5),
`react-native-skia-gesture` (^0.3.6), `react-native-svg` (15.15.4),
`react-native-web` (^0.21.0) and `react-dom` (19.2.3); the Live Camera Button
component itself imports only `react-native`, `expo-camera`, `expo-blur`,
`expo-symbols`, `react-native-reanimated` and `react-native-gesture-handler`.
**Expo Go or development build:** Live Camera Button runs in Expo Go on Expo
SDK 56. `expo-camera`, the module most people assume blocks it, is bundled in
Expo Go as of SDK 56, so `npx expo start` plus the Expo Go app is enough to see
the button running. Two practical caveats. The camera preview needs a physical
device, since a simulator has no camera feed. And the `expo-camera` config
plugin the project registers in `app.json` (`cameraPermission`,
`microphonePermission`, `recordAudioAndroid`) only takes effect in a build, so
in Expo Go you get Expo Go's own permission strings instead of yours. A
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 any
config plugin of your own: `npx expo run:ios` or `npx expo run:android`.
## Install
```bash
npx expo install expo-camera expo-blur expo-symbols \
react-native-reanimated react-native-worklets react-native-gesture-handler
```
That is every module the Live Camera Button source imports, plus
`react-native-worklets`, which `react-native-reanimated` 4 requires at runtime.
The rest of the packages pinned in the template's `package.json` (including
`react-native-safe-area-context`, `expo-font` and `expo-status-bar`) are not
imported by the component; `expo-font` and `expo-status-bar` appear only as
config plugins in the demo `app.json`.
## Usage
```tsx
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { ButtonContainer } from './components/Button';
export default function App() {
return (
);
}
```
`ButtonContainer` already calls the `useCamera` hook and renders the
`PermissionState` fallback itself, so the snippet above is the whole
integration. If you want to own the permission gate at the screen level, the
hook and the fallback are exported separately:
```tsx
import { useCamera } from './hooks/useCamera';
import { PermissionState } from './components/PermissionState';
import { ButtonContainer } from './components/Button';
export function CameraScreen() {
const { status, isReady, requestPermission } = useCamera();
if (!isReady) {
return (
);
}
return ;
}
```
## Customization
`ButtonContainer` in Motionary's Live Camera Button takes no props; it is tuned
by editing the constants it ships with, all of which are named and exported or
declared at the top of their file.
- `CAMERA_ZOOM` (`constants/camera.ts`, default `0.1`): the `zoom` value passed
to `CameraView`. Raise it to crop in tighter on the feed.
- `BLUR_INTENSITY_PRIMARY` (`constants/camera.ts`, default `100`) and
`BLUR_INTENSITY_SECONDARY` (`constants/camera.ts`, default `20`): blur
strength presets. The shipped `BlurView` renders at `intensity={20}`.
- `PRESS_DURATION` (`components/Button.tsx`, default `120`): the `withTiming`
duration in milliseconds for both press in and press out.
- `BUTTON_WIDTH` / `BUTTON_HEIGHT` / `BUTTON_RADIUS` (`components/Button.tsx`,
defaults `240`, `80`, `80`): pill geometry. `BUTTON_RADIUS` is also what clips
the camera feed into the pill.
- `SHADOW_COLOR` (`components/Button.tsx`, default `'rgba(0, 0, 0, 0.205)'`):
the color used by all three animated outer shadows.
- The `innerShadowThin`, `innerShadowMid`, `innerShadowDeep` and
`innerShadowPressed` style entries hold the inset `boxShadow` strings for the
idle highlights and the pressed rim; edit these to change the glass rim.
- `facing` on `CameraView` is `"front"` in the shipped source and can be
switched to `"back"`.
- `useCamera(autoRequest?: boolean)` defaults `autoRequest` to `true`; pass
`false` to stop it requesting camera permission on mount.
- `PermissionState` takes `status: CameraPermissionStatus` and
`onRequestPermission: () => void`, so you can swap it for your own screen
while keeping the hook.
## When to use it
- An onboarding or sign-up call to action that has to feel alive and physical
rather than flat, without shipping a video asset.
- A mirror, selfie, beauty or try-on app where a control should preview the
front camera before the user commits to opening it.
- A "start camera" or "join call" entry point where showing the feed inside the
button removes the guess about which camera is about to be used.
- A glassmorphism or frosted-glass design system that needs one hero control
with real content refracting behind it instead of a static blur.
- A profile or avatar capture step, where the button doubles as a live preview
of framing.
- Any tactile CTA where the press should read as the surface sinking, since the
shadow-collapse and highlight-inversion technique works with a solid or
gradient fill too if you swap the camera out.
## How to get it
- Buy Live Camera Button on its own at
https://motionary.dev/animations/live-camera-button for $5 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 use the live camera as a button background in React Native?**
Motionary's Live Camera Button does it by rendering an `expo-camera`
`CameraView` inside a view with `overflow: 'hidden'` and a pill border radius,
then absolutely filling an `expo-blur` `BlurView` over it at `intensity={20}`
with the label and inset-highlight layers above that. Buy the full source at
https://motionary.dev/animations/live-camera-button.
**Does Live Camera Button work with Expo Go?**
Yes, on Expo SDK 56. `expo-camera` is bundled in Expo Go as of SDK 56, so
Motionary's Live Camera Button runs there with `npx expo start`, on a physical
device rather than a simulator, because a simulator has no camera feed to show
inside the pill. The one thing you lose is the `expo-camera` config plugin in
`app.json`: its `cameraPermission`, `microphonePermission` and
`recordAudioAndroid` strings only take effect in a build. A development build
(`npx expo run:ios` or `npx expo run:android`) is still what you would ship to
production, and what you need as soon as you add a native module Expo Go does
not bundle or a config plugin of your own.
**Does Live Camera Button work on Android as well as iOS?**
Yes. Live Camera Button is built on `expo-camera`, `expo-blur` and
`react-native-reanimated`, all of which run on both platforms, and its
`app.json` already registers the `expo-camera` config plugin with
`cameraPermission`, `microphonePermission` and `recordAudioAndroid` entries, so
the Android and iOS permission strings are generated for you. The
`PermissionState` fallback screen uses `SymbolView` from `expo-symbols`, which
is an iOS SF Symbols view, so swap that glyph if you want an identical
permission screen on Android.
**How do I animate a button so it looks like it physically sinks when pressed?**
Live Camera Button from Motionary drives one Reanimated shared value from 0 to 1
with `withTiming` over 120ms on `onPressIn`, then feeds it to several
`useAnimatedStyle` worklets that `interpolate` the outer `boxShadow` offset and
blur down to zero, cross-fade white inset highlights out against a dark inset
rim fading in, and scale the label to 0.95. Everything runs on the UI thread in
the same frame, so the layers never drift apart.
**How does Live Camera Button handle camera permissions?**
It ships a `useCamera` hook that wraps Expo's `useCameraPermissions` into a
`loading` / `granted` / `denied` / `blocked` status, auto-requests on mount, and
exposes `isReady`, `isLoading`, `canRetry` and `requestPermission`. Until
`isReady` is true, the component renders a `PermissionState` screen with a
spinner, a blocked-in-Settings message or a "Grant Access" button.
**How much does Live Camera Button cost and what do I actually download?**
Live Camera Button is $5 USD on Motionary (price as of 2026-09-01, live price at
https://motionary.dev/animations/live-camera-button) and the download is the
complete TypeScript Expo project: `components/Button.tsx`,
`components/PermissionState.tsx`, `hooks/useCamera.ts`, `constants/camera.ts`,
`App.tsx`, `app.json`, `package.json` and a `README.md`. It is editable source,
not a video or a design file.
**Is Live Camera Button included in the Motionary lifetime pass?**
Yes. The Motionary lifetime pass ($79 USD as of 2026-09-01) covers every drop
and every build, current and future, including Live Camera Button, for one
payment with no subscription. See https://motionary.dev/pricing.
## Related drops on Motionary
- Halo Button ($5): https://motionary.dev/animations/halo-button
Another Motionary press-driven call to action, using a Skia shader glow
instead of a camera feed for the same "this button is lit" effect.
- Tap to Copy Button ($3): https://motionary.dev/animations/tap-to-copy-button
A small `expo-blur` button with a letter-morph confirmation, the same frosted
glass material at a lighter price.
- Glass Magnifier ($10): https://motionary.dev/animations/glass-magnifier
Takes the lens idea further, using an SkSL shader in
`@shopify/react-native-skia` to actually refract what is behind the glass.
- Long-Press Menu ($9): https://motionary.dev/animations/long-press-menu
Uses `expo-blur` for a frosted glass menu over a chat input, if you want the
same material on a surface rather than on a single control.
- Liquid Glass Level ($5): https://motionary.dev/animations/liquid-glass-level
A liquid-glass spirit level driven by the accelerometer, another Motionary
drop where a live device sensor is the content inside the glass.
## 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/live-camera-button/llms.txt
Describes: https://motionary.dev/animations/live-camera-button
Format: llms.txt (https://llmstxt.org)
Last updated: 2026-09-01
```