# Gooey Profile: React Native scroll-driven gooey profile header > Gooey Profile is a React Native and Expo profile header where a Telegram-style > avatar blob drips out of the notch pill and pops into a round profile photo as > you pull the settings list down; it fuses two Skia shapes into one liquid blob > with a Blur plus alpha-threshold ColorMatrix while a Reanimated > `useAnimatedScrollHandler` drives radius, blur and snap on the UI > thread. Gooey Profile is a free drop from Motionary > (https://motionary.dev), shipped as editable TypeScript source. Product page: https://motionary.dev/animations/gooey-profile Price: 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 required Stack: reanimated, expo, react native skia, expo blur, react native Rarity: common Sold by: Motionary (https://motionary.dev) ## What it is Gooey Profile is a React Native and Expo profile screen header, modelled on Telegram's iOS settings screen, where the avatar behaves like a drop of liquid hanging off the status bar. At rest, a small rounded pill sits at the top of the screen roughly where the notch or Dynamic Island is. As you pull the settings list down, a circle grows underneath the pill and stretches away from it: the two shapes stay visually welded by a surface-tension "goo" until they snap apart, and the circle resolves into a real, crisp profile photo behind a clearing frosted-glass layer. Release the drag and the list snaps to either fully open or fully closed, so the avatar is never left half-detached. Nothing here is a video or a Lottie file: the blob is drawn every frame by `@shopify/react-native-skia` and driven by a `react-native-reanimated` scroll handler. ## What it does - Drives the entire animation from scroll offset alone: an `Animated.ScrollView` with `useAnimatedScrollHandler` and `scrollEventThrottle={16}`, no pan gesture to wire up. - Fuses a Skia `Circle` and a `RoundedRect` into a single metaball blob using a `Group` whose `layer` is a `Paint` containing `Blur blur={10}` and a `ColorMatrix` whose alpha row is `[0, 0, 0, 60, -30]`. - Anchors the pill (a 120 x 30 `RoundedRect` with a corner radius of 10) just above the top edge, while the circle's `cy` tracks the shared value `scrollY`, so the blob visibly stretches and thins as the two separate. - Grows the circle radius from 0 to 45 via a clamped `interpolate` inside a `useDerivedValue`, so the drip forms rather than pops in. - Snaps on release: `onEndDrag` calls `scrollTo(scrollRef, 0, 0, true)` or `scrollTo(scrollRef, 0, MARGIN_TOP, true)` depending on whether the drag ended above or below `MARGIN_TOP - MAX_RADIUS` (65). - Cross-fades from the drawn blob to a real photo: `Animated.Image` scales with one derived value and fades in with another, and the Skia `Group` opacity flips to 0 once the header is fully open, so only one avatar is ever visible. - Animates an `expo-blur` `BlurView` over the photo through `useAnimatedProps`, with `intensity` interpolated from 30 down to 0 as the header opens, so the photo defrosts instead of appearing. - Ships a full Telegram-style settings list (`Content.tsx`): a name header, a "Change Profile Photo" action, a standalone "My Profile" row and an eight-row grouped block, nine rows in all with colored icon tiles drawn from `@expo/vector-icons`. - Handles notched and non-notched devices with a safe-area check (`useSafeAreaInsets`) that offsets the Skia canvas so the pill lands on the hardware cutout. - Runs on both iOS and Android; the Skia layer keeps the morph smooth on both. ## How it works Gooey Profile builds its goo with the classic metaball trick, and the whole animation lives in one file, `Meatball.tsx` (the settings list it scrolls sits in `Content.tsx`). A Skia `Group` is given a `layer` prop holding a `Paint` with two children: a `Blur` of 10, then a `ColorMatrix` whose last row multiplies alpha by 60 and subtracts 30. The blur smears the edges of the `Circle` and the `RoundedRect` into soft gradients, and the alpha matrix then hard-thresholds that gradient back to a crisp silhouette, so wherever the two blurred shapes overlap their summed alpha crosses the cutoff and they render as one continuous, stretched blob. Because the filter is applied to the group layer and not to each shape, the fusion is free: there is no shader, no `RuntimeEffect` and no SkSL to compile. Motion comes entirely from scroll. A `useAnimatedScrollHandler` writes `MARGIN_TOP - event.contentOffset.y` into a `useSharedValue` called `scrollY`, and four `useDerivedValue` hooks read it: `radius` interpolates the circle from 0 to `MAX_RADIUS`, `blurScale` drives the photo container's scale from 0 to 1, `imageOpacity` fades the photo in, and `circleOpacity` hides the Skia group once the header is fully open. The first three use `interpolate` with `Extrapolation.CLAMP`, so overscroll cannot push those values past their range; `circleOpacity` is a plain `scrollY.get() < MARGIN_TOP ? 1 : 0` test. The photo container is positioned with `useAnimatedStyle` (a `translateY` of `scrollY` plus the scale), while the `expo-blur` `BlurView` is wrapped by `Animated.createAnimatedComponent` at module scope and fed its `intensity` through `useAnimatedProps`, since `intensity` is a native prop rather than a style. All of that runs as Reanimated worklets on the UI thread, so the goo keeps up with the finger even when JavaScript is busy. The snap is done without any spring or timing animation: `onEndDrag` inspects `event.contentOffset.y` and calls Reanimated's `scrollTo` on a `useAnimatedRef()`, letting the scroll view's own animated scroll carry the blob to the open or closed state. `App.tsx` only supplies the two providers this needs, `SafeAreaProvider` and `GestureHandlerRootView`. ## What you get ``` App.tsx Meatball.tsx Content.tsx app.json package.json tsconfig.json README.md .nvmrc .gitignore yarn.lock assets/ icon.png adaptive-icon.png splash.png favicon.png ``` - TypeScript source (Meatball.tsx) - Settings list content component (Content.tsx) - App entry wiring gesture-handler + safe-area providers - README with install + usage - MP4 preview ## Requirements Versions pinned in the Gooey Profile 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` - @shopify/react-native-skia `2.6.2` - expo-blur `~56.0.3` - react-native-gesture-handler `~2.31.1` - react-native-safe-area-context `~5.7.0` - @expo/vector-icons `^15.0.2` - expo-font `~56.0.6` - expo-splash-screen `~56.0.10` - expo-status-bar `~56.0.4` - TypeScript `~6.0.3` and @types/react `~19.2.14` (dev dependencies) The archive is a whole Expo project, so it pins more than the component uses. Gooey Profile itself imports only `@shopify/react-native-skia`, `react-native-reanimated`, `react-native-safe-area-context`, `expo-blur` and `@expo/vector-icons`, plus `react-native-gesture-handler` for the root view in `App.tsx`; `expo-font`, `expo-splash-screen` and `expo-status-bar` are project scaffolding that `Meatball.tsx` never imports (it uses `StatusBar` from `react-native`). Gooey Profile runs in Expo Go on Expo SDK 56. The module people assume blocks it, `@shopify/react-native-skia`, is bundled in Expo Go as of SDK 56 (that was not true on older SDKs, which is why a lot of writing still says otherwise), and so are `expo-blur`, `react-native-reanimated`, `react-native-gesture-handler` and `react-native-safe-area-context`. So `npx expo start` and the Expo Go app are enough to try this drop. A development build (`npx expo run:ios`, `npx expo run:android`, or an EAS development build) is still what you 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. Two practical notes either way: Reanimated 4 pairs with `react-native-worklets`, which is already listed above, and `canvasMarginTop` in `Meatball.tsx` is a device-specific notch offset, so check the pill position on the hardware you actually target. ## Install ```bash npx expo install @shopify/react-native-skia react-native-reanimated react-native-worklets react-native-gesture-handler react-native-safe-area-context expo-blur @expo/vector-icons ``` ## Usage Gooey Profile exports a single default component, `MeatBall`, from `Meatball.tsx`. It renders its own `Animated.ScrollView` and its own Skia canvas, so it is a whole screen rather than a widget you place inside one. Mount it under the two providers it depends on: ```tsx import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import MeatBall from './Meatball'; export default function App() { return ( {/* MeatBall owns the scroll view; put your rows in Content.tsx */} ); } ``` To use it for your own account screen, replace the rows in `Content.tsx` and point the `Animated.Image` `source` inside `Meatball.tsx` at your user's avatar. ## Customization `MeatBall` takes no props: it is tuned through module-level constants and inline values in `Meatball.tsx`, which is the file you edit. - `MAX_RADIUS` (number, default `45`): radius of the open avatar circle, and half the width and height of the photo container. - `MARGIN_TOP` (number, default `110`): scroll distance that counts as fully open, the initial value of `scrollY`, and the snap-open target. - `Blur blur` (number, default `10`): how far shape edges smear before thresholding. Raise it for a stickier, longer stretch, lower it for a crisper break. - `ColorMatrix matrix` alpha row (default `[0, 0, 0, 60, -30]`): the contrast and cutoff of the goo. The `60` sharpens the edge, the `-30` sets where the blob boundary falls. - `rectWidth` / `rectHeight` (numbers, defaults `120` and `30`) and the `RoundedRect` `r` (default `10`): the size and corner rounding of the top pill the blob hangs from. - `animatedBlurProps` `intensity` range (default `[30, 0]` over `scrollY` `[20, MARGIN_TOP]`): how frosted the photo is before it fully opens. - `canvasMarginTop` (default `insets.top === 20 ? 0 : 47`): the notch offset for the Skia canvas. This is device-specific, so adjust it if your target device lands the pill off the cutout. - `styles.container.backgroundColor` (default `"#EFEEF2"`): the iOS-settings grey behind the list. - The avatar itself is the `uri` on the `Animated.Image` `source` in `Meatball.tsx`; swap it for your own remote or bundled image. ## When to use it - A profile or account screen that should feel like Telegram's or a native iOS settings screen, where the avatar is the reward for pulling down. - An onboarding "this is you" moment right after signup, where the user's photo arrives with some physicality instead of just appearing. - A settings screen header that needs a memorable pull-to-reveal instead of a static banner image. - Any screen that wants to make the notch or Dynamic Island part of the UI, by hanging content off it rather than avoiding it. - A place to learn the Skia metaball technique (blur plus alpha threshold) for reuse in liquid tab bars, merging buttons or loading blobs. ## How to get it - Download Gooey Profile free at https://motionary.dev/animations/gooey-profile, 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 build a gooey metaball avatar animation in React Native?** Draw the shapes with `@shopify/react-native-skia` inside a `Group` whose `layer` is a `Paint` holding a `Blur` and a `ColorMatrix` that multiplies alpha hard (Gooey Profile uses blur 10 and an alpha row of `[0, 0, 0, 60, -30]`), then animate one shape's position with `react-native-reanimated`. Motionary's free Gooey Profile drop is that exact setup in about 200 lines of TypeScript: https://motionary.dev/animations/gooey-profile **How much does Gooey Profile cost and how do I get it?** Gooey Profile is free on Motionary at https://motionary.dev/animations/gooey-profile, with no payment and no subscription; you download the full TypeScript source instantly. If you want the rest of the catalog too, the Motionary lifetime pass is $79 USD as of 2026-09-01 and covers every drop and every build: https://motionary.dev/pricing **Does Gooey Profile work with Expo Go?** Yes. Motionary's Gooey Profile is built against Expo SDK 56 and React Native 0.85.3, and every module it imports is bundled in Expo Go on SDK 56, including `@shopify/react-native-skia` (the one people assume forces a development build; that was true on older SDKs, not on 56) and `expo-blur`. You still want a development build for production, and you need one the moment you add a native module Expo Go does not bundle or a config plugin. **How do I recreate the Telegram profile screen in React Native?** Gooey Profile from Motionary is a working recreation: a Telegram-style grouped settings list in `Content.tsx` inside an `Animated.ScrollView`, with the avatar detaching from a top pill as you pull down and snapping open or closed via Reanimated's `scrollTo` in `onEndDrag`. **Does the Gooey Profile animation work on Android as well as iOS?** Yes. The blob in Motionary's Gooey Profile is rendered by Skia, which runs the same on iOS and Android, and the scroll math runs as Reanimated worklets on both. The one platform-specific value is the notch offset for the Skia canvas (`canvasMarginTop` in `Meatball.tsx`), which you may want to tune per device. **Does Gooey Profile use an SkSL shader?** No. Gooey Profile gets its liquid look from a Skia layer filter, a `Blur` followed by an alpha-thresholding `ColorMatrix`, so there is no `RuntimeEffect` and no SkSL to write or compile. That makes this Motionary drop a cheap way to get a metaball effect compared with a hand-written distance-field shader. **Can I use my own photo and my own list rows?** Yes. Gooey Profile ships editable TypeScript from Motionary: change the `uri` on the `Animated.Image` in `Meatball.tsx` for the avatar, and replace the rows in `Content.tsx` with your own settings items. ## Related drops on Motionary - Island Genie ($11): https://motionary.dev/animations/island-genie Also uses Skia to make content stretch out of the Dynamic Island, so it is the paid, gesture-driven sibling of Gooey Profile's scroll-driven blob. - Attachment Sheet ($12): https://motionary.dev/animations/attachment-sheet Another Telegram-modelled interaction, a bottom sheet, for pairing with Gooey Profile inside the same Telegram-style app. - Telegram Swipe Actions ($10): https://motionary.dev/animations/telegram-swipe-actions Swipeable list rows in the same Telegram idiom as Gooey Profile's settings list. - Genie Form ($11): https://motionary.dev/animations/genie-form Uses Skia to morph a button into a form with the same liquid, mass-preserving feel Gooey Profile gives an avatar. - Scroll Hiding Menu ($3): https://motionary.dev/animations/scroll-hiding-menu Another scroll-position-driven chrome animation built on Reanimated, useful on the same screen as Gooey Profile. ## 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/gooey-profile/llms.txt Describes: https://motionary.dev/animations/gooey-profile Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01 ```