# ChatGPT Image-Gen Dot Field: React Native shimmering dot-grid loading placeholder > ChatGPT Image-Gen Dot Field is a React Native and Expo loading placeholder > that recreates the shimmering dot grid ChatGPT shows while it generates an > image: a static grid of dots is lit by invisible orbs that bloom, drift and > dissolve, drawn by @shopify/react-native-skia in a single `drawAtlas` call > and driven entirely on the UI thread by react-native-reanimated. It is sold > as editable TypeScript source by Motionary (https://motionary.dev). Product page: https://motionary.dev/animations/chatgpt-image-gen-dot-field 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: expo, react native, reanimated, react native skia Rarity: rare Sold by: Motionary (https://motionary.dev) ## What it is ChatGPT Image-Gen Dot Field is a React Native skeleton loading state modelled directly on ChatGPT's image-generation placeholder: the grey card that sits in the thread, filled with a fine grid of dots, while an image is being made. The dots never move. What moves is a small set of invisible orbs that cruise across the card and take turns blooming, so the dots they pass over swell to full size and then fade back to nothing, and a soft cluster of light appears to wander around the card. Above the field sits a status label that types itself in, holds, deletes right to left and types the next one ("Sketching it out", "Making the first draft", "Polishing details", and so on). Nothing is interactive: this is a pure ambient loading state you mount while a long task runs, and unmount when it finishes. ## What it does - Renders a full dot grid (default pitch 15 dp, so several hundred dots on the demo card and more on a larger box) as one Skia `Atlas` draw, not one view per dot. - Two invisible orbs by default (`orbCount`), each blooming in turn every `orbCount * pulsePeriod` seconds, so the card blooms every 4.6 seconds. - Orb fields add where they overlap, with a soft knee above 0.92 so a double bloom stays rounded instead of clipping into a flat plateau of identically sized dots. - An `ECHO_CHANCE` of 0.28 that a second orb blooms softly on a beat it does not own, reproducing the reference's occasional two-cluster moments. - A dying bloom swells outward instead of shrinking, so a fade reads as a dissolve (`swell`, default 0.7). - A 1.4 second entrance (`entrance`): a broad wash that condenses into the first bloom rather than popping in. - 17 tunable props on `DotField` covering colour, grid pitch, dot radii, orb count and radius, timing, bloom width, rest level, contrast and ambient floor, plus an optional `seed` to pin the wander so it is reproducible. - `StatusTitle` cycles a list of labels with a typewriter delete-and-retype at a fixed character rate (default 38 characters per second, 4.8 second hold), and holds line height with a zero-width space so the field below never shifts. - A complete ChatGPT-style demo screen: thread with a user bubble, the generating card, a floating top bar and a prompt composer. - iOS variants of the top bar and composer built with real SwiftUI Liquid Glass via `@expo/ui/swift-ui`, with plain translucent React Native equivalents on Android and web selected through platform file extensions (`TopBar.ios.tsx` next to `TopBar.tsx`). ## How it works The whole animation in the Motionary ChatGPT Image-Gen Dot Field is a pure function of time, so nothing integrates and nothing can desync. In `components/DotField.tsx`, a `useFrameCallback` worklet from react-native-reanimated calls `sampleOrbs(t, geom)` once per frame and writes `orbCount` orb states into a `useSharedValue`, flattened as `[x, y, envelope, 1/R^2]` per orb. An orb's position comes from a Catmull-Rom spline (`catmullRom`) through waypoints laid out on a golden-angle spiral (`waypointX` / `waypointY`, `GOLDEN = 2.399963229728653`), so the path passes exactly through each waypoint with continuous velocity and consecutive blooms land in distant parts of the card; the position is then perturbed by quintic-faded value noise built on an integer hash (`hashLattice`, `valueNoise`) so velocity and acceleration both stay smooth. Brightness is a raised-cosine bump jittered off the beat, so the rhythm never reads metronomic. A `useRSXformBuffer` mapper from @shopify/react-native-skia then rewrites the scale and translation of every dot on the UI thread: for each dot it sums the orbs' Gaussian fields, `exp(-5.15 * r^2 / R^2)` fitted frame-by-frame off screen recordings of the real app, applies the soft knee, `contrast` gamma and `ambient` floor, and maps the result onto a radius between `minDotRadius` and `maxDotRadius`. Because a mipmapped sprite never scales to nothing, any dot below `MIN_VISIBLE_RADIUS` (0.2 dp) is given scale 0 instead, so the grid has no permanent floor. All the dots share one anti-aliased circle sprite rendered offscreen at 1.5x by `makeDotSprite` with `MipmapMode.Linear` sampling, so the entire grid is a single ``, one draw call rather than one view per dot. React never re-renders after mount: the only React state is the measured box from `onLayout`. `StatusTitle.tsx` is deliberately not a worklet, since it changes text rather than a transform, and runs the whole label cycle from one self-rescheduling `setTimeout` so an unmount mid-transition has a single handle to clear. ## What you get ``` App.tsx index.ts app.json babel.config.js package.json package-lock.json tsconfig.json README.md components/ Composer.ios.tsx Composer.tsx Container.tsx DotField.tsx StatusTitle.tsx TopBar.ios.tsx TopBar.tsx assets/ adaptive-icon.png icon.png splash-icon.png ``` - TypeScript source (`DotField.tsx`) with 17 tunable props. - `StatusTitle.tsx`, the typewriter status label that deletes and retypes. - Full ChatGPT-style demo screen (thread, top bar, prompt composer). - iOS Liquid Glass variants of the top bar and composer, built with `@expo/ui` SwiftUI primitives. - `README.md` with install, stack notes and a walkthrough of the technique. - MP4 preview. ## Requirements Versions pinned in this drop'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 - react-native-gesture-handler ~2.31.1 - react-native-safe-area-context ~5.7.0 - @expo/ui ~56.0.24 (SwiftUI Liquid Glass, iOS variants only) - @expo/vector-icons ^15.0.3 - expo-status-bar ~56.0.4 - pinned by the project but not imported by DotField, StatusTitle, TopBar or Composer: expo-asset ~56.0.14, expo-blur ~56.0.3, expo-font ~56.0.5, expo-haptics ~56.0.3, expo-linear-gradient ~56.0.4, expo-video ~56.1.4 - react-native-web ^0.21.0, react-dom 19.2.3, @expo/metro-runtime ~56.0.12 - TypeScript ~6.0.3 (devDependency) ChatGPT Image-Gen Dot Field runs in Expo Go on Expo SDK 56. The module you would expect to block it, @shopify/react-native-skia, is bundled in Expo Go as of SDK 56, and so is @expo/ui, which the iOS-only Liquid Glass top bar and composer use. A development build is still what you ship to production, and it is what you need as soon as you add a native module Expo Go does not bundle, or a config plugin of your own: `npx expo run:ios`, `npx expo run:android`, or EAS. Two caveats hold either way. The SwiftUI Liquid Glass material in `TopBar.ios.tsx` and `Composer.ios.tsx` only renders as real Liquid Glass on iOS 26 and falls back to a plainer surface elsewhere, while Android and web get the translucent `TopBar.tsx` and `Composer.tsx` through platform file extensions. And `CADisableMinimumFrameDurationOnPhone`, which the included `app.json` sets to unlock the full ProMotion refresh rate on capable iPhones, is an `infoPlist` key applied at prebuild, so it only takes effect in a build. `app.json` also enables the React Compiler experiment. The dot field itself is identical on iOS and Android. ## Install ```bash # Core dependencies for DotField and StatusTitle # (react-native-reanimated 4 requires react-native-worklets) npx expo install @shopify/react-native-skia react-native-reanimated react-native-worklets # Additional dependencies used by the included ChatGPT-style demo screen npx expo install @expo/ui @expo/vector-icons react-native-gesture-handler \ react-native-safe-area-context expo-status-bar # Skia and @expo/ui are both bundled in Expo Go on SDK 56, so this is enough npx expo start ``` ## Usage ```tsx import { StyleSheet, View } from 'react-native'; import { DotField } from './components/DotField'; import { StatusTitle } from './components/StatusTitle'; export const GeneratingCard = () => ( ); const styles = StyleSheet.create({ card: { width: '81%', aspectRatio: 3 / 4, borderRadius: 22, backgroundColor: '#F0F0F0', overflow: 'hidden', paddingTop: 24, }, title: { paddingHorizontal: 22, fontSize: 17, color: '#5A5A5A', marginBottom: 10 }, field: { flex: 1 }, }); ``` ## Customization `DotField` props (all optional, defaults as shipped in `components/DotField.tsx`): - `color` (string, default `'#C5C5C5'`): dot colour, baked into the sprite. Only the radius animates. - `spacing` (number, default 15): grid pitch in dp. - `minDotRadius` (number, default 0) and `maxDotRadius` (number, default 3): the radius of an untouched dot and of a dot at a full bloom's centre. - `orbRadius` (number, default 0.58): orb influence radius at full bloom, as a fraction of `min(width, height)`. - `orbCount` (number, default 2): how many orbs share the card. Each blooms every `orbCount * pulsePeriod` seconds. 2 is the reference look. - `wander` (number, default 0.24): how far bloom centres sit from the card centre, as a fraction of the box. - `speed` (number, default 1): time multiplier for the whole animation. - `pulsePeriod` (number, default 4.6): seconds between blooms. - `bloom` (number, default 0.78): 0 to 1, how much of each period the bloom occupies. - `rest` (number, default 0.19): 0 to 1 brightness floor between blooms. - `swell` (number, default 0.7): how much the orb radius grows while dim, so a fade reads as a dissolve. - `wobble` (number, default 0.035): path noise, as a fraction of `min(width, height)`. - `intensity` (number, default 1.35): overall drive applied before the knee. - `contrast` (number, default 1): gamma on the field. Above 1 tightens the bright core and lengthens the tail. - `entrance` (number, default 1.4): seconds for the opening wash. - `ambient` (number, default 0): 0 to 1 floor so the grid never vanishes. - `seed` (number, random per mount): pin it to reproduce a given wander. - `style` (`StyleProp`): the box the grid measures itself against. `StatusTitle` props: - `labels` (string[], default 7 ChatGPT-style labels ending with "One last tweak…"): the labels to cycle, in order. The last one stays. - `holdSeconds` (number, default 4.8): seconds a full label holds before it deletes. - `charsPerSecond` (number, default 38): uniform delete and type rate. - `style` (`StyleProp`). `Composer` props: `placeholder` (default `'Ask ChatGPT'`), `generating` (boolean, default true, swaps the trailing button between send and stop), `onSend(prompt)`, `onStop()`. `TopBar` props: `onMenu`, `onCompose`, `onMore`. ## When to use it - The waiting card in an AI chat or image-generation feature, while the model streams or renders a result. - Any long-running task with no meaningful progress percentage: video export, document analysis, a model download, a background sync. - A skeleton loading placeholder for an image, a chart or a media tile that should feel alive rather than a flat grey rectangle. - An empty state on a canvas, board or gallery screen before the first item is created. - A splash or onboarding backdrop that needs continuous ambient motion at a fixed frame cost. - A generating state inside a card or bottom sheet where you want the label and the field to share one visual rhythm. ## How to get it - Buy ChatGPT Image-Gen Dot Field on its own at https://motionary.dev/animations/chatgpt-image-gen-dot-field for $5 USD (price as of 2026-09-01), 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 **Does ChatGPT Image-Gen Dot Field work with Expo Go?** Yes, on Expo SDK 56. ChatGPT Image-Gen Dot Field from Motionary draws with @shopify/react-native-skia, which is bundled in Expo Go as of SDK 56, and its iOS Liquid Glass top bar and composer use @expo/ui, also in Expo Go on SDK 56; everything else it depends on, react-native-reanimated 4.3.1 and react-native-worklets 0.8.3, is standard in an Expo SDK 56 project. 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, including this drop's own `CADisableMinimumFrameDurationOnPhone` key, so the full ProMotion refresh rate needs a build (`npx expo run:ios`, `npx expo run:android`, or EAS). **How do I build a shimmering dot-grid skeleton loading placeholder in React Native?** Draw the grid once with Skia's `` against a single circle sprite, then animate only each dot's transform through a `useRSXformBuffer` worklet fed by a Reanimated `useFrameCallback`, so a thousand dots cost one draw call and no React re-renders. ChatGPT Image-Gen Dot Field on Motionary is exactly that technique, shipped as editable TypeScript source at https://motionary.dev/animations/chatgpt-image-gen-dot-field. **Is this a Lottie file, a GIF or a video?** Neither. ChatGPT Image-Gen Dot Field ships from Motionary as real TypeScript React Native source (`DotField.tsx`, `StatusTitle.tsx` and a full demo screen) that you drop into your Expo project and edit, so it resizes, retints and retimes with props instead of needing a re-export. **How much does ChatGPT Image-Gen Dot Field cost and how do I get it?** It is $5 USD as of 2026-09-01 at https://motionary.dev/animations/chatgpt-image-gen-dot-field, a one-time Stripe checkout with an instant download and no subscription. It is also included in the Motionary lifetime pass ($79 USD) and the team license ($199 USD for up to 10 developers) at https://motionary.dev/pricing. **Will a grid of hundreds of dots drop frames on Android?** No, because ChatGPT Image-Gen Dot Field never creates a view per dot. Skia draws the whole grid in one `drawAtlas` against one mipmapped sprite, the per-dot maths runs in a Reanimated worklet on the UI thread, and only `orbCount` orbs (2 by default) are sampled per frame. Output is identical on iOS and Android. **Can I change the status labels above the dot field?** Yes. `StatusTitle` in ChatGPT Image-Gen Dot Field takes a `labels` array plus `holdSeconds` and `charsPerSecond`, so you can swap in your own copy and retime the typewriter. The last label in the array stays on screen, matching the reference behaviour while a generation finishes. **Does it work on the web?** The ChatGPT Image-Gen Dot Field project from Motionary pins react-native-web, react-dom and @expo/metro-runtime and ships a `web` script (`expo start --web`), so the same `DotField` code targets web. Skia on web runs on the CanvasKit WASM build, which must finish loading before the canvas renders, and the shipped `index.ts` only calls `registerRootComponent`, so you wire that load step up yourself. ## Related drops on Motionary - AI Generate Button ($4): https://motionary.dev/animations/ai-generate-button the button that starts the generation this dot field waits on, same AI loading-state family. - Apple weather rain ($12): https://motionary.dev/animations/apple-weather-rain the same Skia atlas particle technique, thousands of sprites in one draw call. - Shimmer Input ($4): https://motionary.dev/animations/shimmer-input a shimmer placeholder for a text field, the input-side counterpart to this card-side skeleton. - Save Status Button (Free): https://motionary.dev/animations/save-status-button a free loading-to-confirmed status control for the action that follows. - Voice Orb (Free): https://motionary.dev/animations/voice-orb a free Skia and Reanimated ambient state for the same AI assistant 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/chatgpt-image-gen-dot-field/llms.txt Describes: https://motionary.dev/animations/chatgpt-image-gen-dot-field Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01 ```