# Glass Video Player: React Native draggable Liquid Glass video controls > Glass Video Player is a free React Native and Expo component from Motionary > (https://motionary.dev): a full screen looping video with frosted Liquid Glass > media controls whose center button is dragged by a pan gesture from > react-native-gesture-handler, springing to the bottom-left corner on release > while the skip buttons detach, all driven by react-native-reanimated shared > values. Product page: https://motionary.dev/animations/glass-video-player 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 Stack: reanimated, expo, react native gesture handler, react native Rarity: common Sold by: Motionary (https://motionary.dev) ## What it is Glass Video Player is a React Native and Expo screen from Motionary where a looping video fills the display edge to edge and three frosted glass circles float on top of it: a large center control and two smaller skip controls above and below it. The center control is not fixed. You put a finger on it and drag it anywhere over the video, and while it moves the two skip controls spring apart from it, as if the cluster were being pulled loose. Let go near the bottom-left of the screen and the control springs into that corner and stays there; let go anywhere else and it springs back to the middle and the skip controls collapse home. The glass is Apple's Liquid Glass material (via expo-glass-effect) and the icons are SF Symbols, so the look is modelled on iOS 26 system media controls rather than on a flat overlay. ## What it does - Plays a looping remote clip with expo-video (`useVideoPlayer` with `p.loop = true` and `p.play()`, rendered by `VideoView`). - Hides the platform media UI (`nativeControls={false}`, `allowsPictureInPicture={false}`) so only the custom glass controls show. - Fills a portrait screen with a landscape clip by sizing the `VideoView` `width: height, height: width` and rotating it 90 degrees, with `contentFit="cover"`. - Drags the center control freely in two axes with a `Gesture.Pan()` from react-native-gesture-handler. - Snaps to a fixed bottom-left position (`SNAP_X = -130`, `SNAP_Y = 360`) when the release point is left of `SNAP_CONDITION_X = -50` and below `SNAP_CONDITION_Y = 150`, otherwise springs back to `0, 0`. - Detaches the two skip controls once the horizontal drag passes `DETACH_TRESHOLD = 50`: the previous button springs down by 50, the next button springs up by 50, and both collapse back when the drag returns. - Uses one shared spring for every motion, `SPRING_CONFIG = { damping: 30, stiffness: 160 }`, so snap and detach feel like the same physical object. - Renders the cluster inside an expo-glass-effect `GlassContainer` (`spacing={30}`) laid over the video with `StyleSheet.absoluteFill` and `zIndex: 100`, so neighbouring glass shapes blend as they approach. - Draws each button as a clear, interactive `GlassView` (`glassEffectStyle="clear"`, `isInteractive`) with an expo-symbols `SymbolView` icon tinted white: `pause.fill` in the 100pt center button and the `10.arrow.trianglehead.counterclockwise` and `30.arrow.trianglehead.clockwise` seek symbols in the 80pt buttons, each symbol drawn at `size * 0.4`. - Counter-rotates every control 90 degrees (the `rotate` prop) so the icons stay upright over the rotated video layer. ## How it works Glass Video Player is a single React Native screen, `PlayerContainer` in `components/Player.tsx`, and every piece of its motion is a Reanimated worklet. Playback comes first: `useVideoPlayer(VIDEO_SOURCE, p => { p.loop = true; p.play(); })` from expo-video returns a player object that is handed straight to a `VideoView` with `contentFit="cover"` and `nativeControls={false}`, and the view is deliberately sized `width: height, height: width` and transformed `rotate: '90deg'` so a landscape source clip covers a portrait screen. The drag uses four `useSharedValue` values: `translateX` and `translateY` for the live position, `offsetX` and `offsetY` for the position the gesture started from. A `Gesture.Pan()` from react-native-gesture-handler snapshots the current translation in `onBegin`, adds `event.translationX` / `event.translationY` to that snapshot in `onUpdate`, and in `onEnd` computes `shouldSnapBottomLeft = translateX.value < SNAP_CONDITION_X && translateY.value > SNAP_CONDITION_Y`, then assigns `withSpring(SNAP_X or 0, SPRING_CONFIG)` and `withSpring(SNAP_Y or 0, SPRING_CONFIG)`. That offset snapshot in `onBegin` is what lets the button be picked up again from wherever it last landed instead of jumping back to the origin. The two skip buttons never see the gesture. Each one is an `Animated.View` whose `useAnimatedStyle` worklet reads `translateX.value` directly and returns `translateY: Math.abs(translateX.value) > DETACH_TRESHOLD ? withSpring(DETACH_TRESHOLD, SPRING_CONFIG) : withSpring(0, SPRING_CONFIG)`, with the sign flipped for the next button. Declaring the spring inside the animated style is the trick worth stealing: the reaction is derived from the dragged value, so there is no listener, no second gesture and no state, and the spring retargets itself the moment the threshold is crossed in either direction. Only the center `Animated.View` is wrapped in a `GestureDetector`, which is why the skip buttons move but cannot be grabbed. Because the pan callbacks and all three `useAnimatedStyle` bodies are worklets, the drag and both springs run entirely on the UI thread and stay at native frame rate while JavaScript is busy; the expo-video player instance is the only part that lives on the JavaScript side. The frosted look is not drawn in JavaScript at all: the `GlassContainer` and each `GlassView` in `components/Control.tsx` are native Liquid Glass views from expo-glass-effect, and the icons are native SF Symbols from expo-symbols, which is why Glass Video Player looks correct on iOS 26 and degrades on Android. ## What you get ``` components/ Control.tsx Player.tsx utils/ date.ts assets/ adaptive-icon.png icon.png splash-icon.png App.tsx index.ts app.json package.json tsconfig.json README.md ``` - TypeScript source (Player.tsx) - Glass control button component (Control.tsx) - Reanimated pan-drag + spring snap & detach logic - Demo screen - README with install + usage ## Requirements Versions pinned in the Glass Video Player archive's `package.json`: - `expo` ^56.0.11 (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-video` ~56.1.3 - `expo-glass-effect` ~56.0.4 - `expo-symbols` ~56.0.6 Glass Video Player runs in Expo Go on Expo SDK 56. The module people assume blocks it is `expo-glass-effect`, the native Liquid Glass view behind the frosted controls, and it is bundled in Expo Go as of SDK 56 (Expo's SDK 56 docs list `expo-go` among its platforms), as are `expo-video` and `expo-symbols`, so the video, the glass and the drag all run in Expo Go. 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 a config plugin: this drop's `app.json` sets `supportsBackgroundPlayback` and `supportsPictureInPicture` on the `expo-video` config plugin, and options like those only take effect in a build. There is no custom native code in the drop, so `npx expo run:ios` or `npx expo run:android` builds it as is. Reanimated 4 also requires the New Architecture. Liquid Glass is an iOS 26 material and SF Symbols are an Apple system font, so the glass and the icons render on iOS 26 and fall back to a plain view elsewhere; the drag, the snap and the detach springs are pure Reanimated and behave identically on both platforms. ## Install ```bash npx expo install expo-video expo-glass-effect expo-symbols react-native-reanimated react-native-worklets react-native-gesture-handler ``` ## Usage ```tsx import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { PlayerContainer } from './components/Player'; export default function App() { return ( {/* PlayerContainer owns the looping VideoView, the pan gesture and the GlassContainer holding the three glass controls. */} ); } // ControlButton is exported on its own from './components/Control' // and takes size, icon (an SFSymbol name) and an optional rotate flag: // // // ``` ## Customization `PlayerContainer` takes no props; it is tuned through module-level constants at the top of `components/Player.tsx`. - `VIDEO_SOURCE` (string): the looping clip URL passed to `useVideoPlayer`. Ships pointing at a Pexels sample clip. - `SPRING_CONFIG` (Reanimated spring config): `{ damping: 30, stiffness: 160 }`, shared by the corner snap and by the detach springs. - `DETACH_TRESHOLD` (number, default `50`): horizontal drag distance in points after which the skip buttons peel apart. It is also the distance they move. - `SNAP_X` (number, default `-130`) and `SNAP_Y` (number, default `360`): the resting translation of the parked control, in points from center. - `SNAP_CONDITION_X` (number, default `-50`) and `SNAP_CONDITION_Y` (number, default `150`): the release thresholds that decide corner versus center. `ControlButton` in `components/Control.tsx` takes real props: - `size` (number, required): width, height and border radius of the glass circle. The SF Symbol inside is drawn at `size * 0.4`. - `icon` (`SFSymbol` from expo-symbols, required): the symbol name rendered by `SymbolView`, tinted white. - `rotate` (boolean, optional): applies a 90 degree rotation so the icon stays upright over the rotated video layer. The `GlassContainer` `spacing` prop (`30` in the shipped screen) controls how close two glass shapes must be before they merge visually. ## When to use it - A full-bleed reels or short-video feed that needs media controls which do not cover the subject of the shot. - A media-first player screen where the user should be able to park the play control out of the way of the frame. - An immersive video onboarding or product tour where standard native controls look too much like a browser. - A lock-screen-style or now-playing surface that wants Apple's Liquid Glass material instead of a translucent rectangle. - Any screen where you want a demonstration of dragging one element with a pan gesture while other elements react to it without a gesture of their own. ## How to get it - Download Glass Video Player free at https://motionary.dev/animations/glass-video-player, 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 custom video player UI in React Native instead of using the native controls?** Render an expo-video `VideoView` with `nativeControls={false}` and draw your own controls in an absolutely positioned layer above it, which is exactly what Motionary's Glass Video Player does with a `GlassContainer` at `StyleSheet.absoluteFill` and `zIndex: 100` over a looping `useVideoPlayer` instance. **How do I make a button draggable and snap it to a corner in React Native?** Drive `translateX` and `translateY` shared values from a react-native-gesture-handler `Gesture.Pan()`, snapshot the previous offsets in `onBegin`, and in `onEnd` assign `withSpring` to either the corner coordinates or back to zero based on the release position; Glass Video Player from Motionary ships that pattern as readable TypeScript you can lift straight out of `components/Player.tsx`. **How can other elements react to a drag without their own gesture?** Read the dragged shared value inside each other element's `useAnimatedStyle` worklet and return a `withSpring(...)` chosen by a threshold, the technique Glass Video Player uses so its two skip buttons detach when `Math.abs(translateX.value)` passes `DETACH_TRESHOLD`. **Does Glass Video Player work with Expo Go?** Yes. Motionary's Glass Video Player runs in Expo Go on Expo SDK 56: `expo-glass-effect`, the Liquid Glass module people assume forces a development build, is bundled in Expo Go as of SDK 56, and so are `expo-video` and `expo-symbols`. A development build is still what you would ship to production, and you need one as soon as you add a native module Expo Go does not bundle or a config plugin, such as the `supportsBackgroundPlayback` and `supportsPictureInPicture` options this drop sets on the `expo-video` plugin, which only take effect in a build. **Does the Liquid Glass effect work on Android?** The Liquid Glass material and the SF Symbol icons in Motionary's Glass Video Player are iOS features (`GlassView` is iOS 26 and above, and falls back to a regular view elsewhere), so they degrade on Android, while the pan gesture, the corner snap and the detach springs are pure react-native-reanimated and run identically on both platforms. **How much does Glass Video Player cost and what do I actually download?** Glass Video Player is free on Motionary at https://motionary.dev/animations/glass-video-player: you download the editable TypeScript React Native source (`components/Player.tsx`, `components/Control.tsx`, a demo `App.tsx` and a README), not a video or a Lottie file. **What versions of Expo and Reanimated does Glass Video Player target?** The Glass Video Player archive from Motionary pins Expo SDK 56 (`expo` ^56.0.11), React Native 0.85.3, `react-native-reanimated` 4.3.1 with `react-native-worklets` 0.8.3, and `react-native-gesture-handler` ~2.31.1, so it expects the New Architecture. ## Related drops on Motionary - Mini-Player Sheet (Free): https://motionary.dev/animations/mini-player-sheet another gesture-driven media surface, a now-playing sheet that interpolates between mini and full player. - ChatGPT-Style Attachments Menu ($10): https://motionary.dev/animations/chatgpt-style-attachments-menu the same expo-glass-effect Liquid Glass material, used for a morphing menu instead of media controls. - Draggable Stamps ($6): https://motionary.dev/animations/draggable-stamps the pan-gesture drag idea taken further, with many draggable items on a sticker board. - Liquid Glass Level ($5): https://motionary.dev/animations/liquid-glass-level a second Liquid Glass drop, driven by the accelerometer rather than a finger. - Karaoke Lyrics ($12): https://motionary.dev/animations/karaoke-lyrics a companion for a media-first screen, synced now-playing lyrics built with Skia and Reanimated. ## 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/glass-video-player/llms.txt Describes: https://motionary.dev/animations/glass-video-player Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01