Upload one logo and get launch screen assets for Android 12+, iOS and Expo — densities, themes.xml, LaunchScreen.storyboard and the app.json block, with a live preview of the circular mask that crops most splash screens.
A transparent PNG works best — 1024×1024 or larger. The background colour is set separately, never baked into the file.
Android 12+ masks the splash icon to a circle on a 288dp canvas and discards everything outside it. Staying at or below 67% (192dp) is what keeps a logo intact.
Exported at @1x, @2x and @3x and written into the storyboard constraint.
The width expo-splash-screen renders the icon at. Expo's default is 200.
Enter splash for splash.png. Leave blank to keep the default names. The .png extension is added automatically.
Everything runs in your browser. No upload, no storage.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Parent must be Theme.SplashScreen, from androidx.core:core-splashscreen.
The library backports the Android 12 splash API down to API 21, so this
single theme is the whole implementation on every supported version.
-->
<style name="Theme.App.SplashScreen" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
<item name="windowSplashScreenAnimationDuration">300</item>
<!--
The theme the activity switches to once the splash is dismissed.
Point this at your real app theme; leaving it wrong is what causes
the splash to linger or the app to flash an unstyled window.
-->
<item name="postSplashScreenTheme">@style/AppTheme</item>
</style>
</resources>
{
"expo": {
"plugins": [
[
"expo-splash-screen",
{
"image": "./assets/images/splash-icon.png",
"imageWidth": 200,
"resizeMode": "contain",
"backgroundColor": "#FFFFFF",
"dark": {
"image": "./assets/images/splash-icon-dark.png",
"backgroundColor": "#0F172A"
}
}
]
]
}
}Almost every broken launch screen traces back to one API change.
Before Android 12, an app drew its own splash: a full-screen bitmap set as windowBackground, cut once per density and stretched to fit whatever ratio the device happened to have. Android 12 took that job away. The system now draws the launch screen itself from your theme, and it masks windowSplashScreenAnimatedIcon to a circle.
The canvas is 288dp, but only the middle 192dp survives — the outer third is discarded. Artwork that filled the old full-screen image loses its edges, wordmarks lose their first and last letters, and the app ships before anyone notices because the emulator most people test on is still on an older API level.
The same rule reaches further than it looks. expo-splash-screen compiles down to this API, so Expo apps inherit the mask after prebuild. And androidx.core:core-splashscreen backports the behaviour to API 21, so it applies on older devices too as soon as you adopt the library.
The rule to remember: keep the logo inside the middle two-thirds of the canvas. The size slider above marks that limit, and the preview ghosts whatever falls outside it so you can see the crop before you build.
Every dimension the generator writes, if you would rather export by hand.
| Density | Scale | Canvas (288dp) | Safe zone (192dp) |
|---|---|---|---|
| mdpi | 1x | 288 × 288 px | 192 px |
| hdpi | 1.5x | 432 × 432 px | 288 px |
| xhdpi | 2x | 576 × 576 px | 384 px |
| xxhdpi | 3x | 864 × 864 px | 576 px |
| xxxhdpi | 4x | 1152 × 1152 px | 768 px |
Static launch images have been unsupported since Xcode 12; a storyboard is the only accepted launch screen. The logo width is configurable above and written into the storyboard constraint.
The plugin compiles to the native splash APIs, so the Android mask applies after prebuild. Both config shapes are written into the ZIP.
Four steps, about two minutes, entirely in your browser.
Drop in a PNG at 1024x1024 or larger with a transparent background. Leave the background colour out of the file — every modern platform takes it from configuration instead, and a baked-in background shows as a clipped square behind Android's circular mask.
Android 12 and newer mask the splash icon to a circle and discard the outer third of the 288dp canvas. The size slider marks the 67% limit and the preview ghosts anything that would be clipped, so you can see the crop before you build.
The tool reads the palette out of your logo and offers light and dark backgrounds built from its hue, then checks the contrast so the artwork does not dissolve into the backdrop. You can also pick any colour by hand, and upload a second logo for dark mode.
Export a ZIP with Android drawable densities plus themes.xml, an iOS imageset with LaunchScreen.storyboard and a colour set, and Expo assets with the app.json plugin block. A README lists the exact destination path for each folder.
The drawable canvas is 288x288 dp — 288px at mdpi, 432px hdpi, 576px xhdpi, 864px xxhdpi and 1152px xxxhdpi. Your artwork must fit inside the centre 192dp, because the system masks the icon to a circle and throws away the outer third. If you set windowSplashScreenIconBackgroundColor the visible circle shrinks to 240dp and the artwork budget to 160dp, which is the same two-thirds proportion.
Android 12 replaced the old windowBackground splash with a system-drawn one that masks windowSplashScreenAnimatedIcon to a circle. A logo that filled the old full-screen image will lose its edges. The fix is to scale the artwork down to the inner two-thirds of the canvas; this generator marks that limit on the size slider and ghosts the clipped area in the preview.
1024x1024 px with a transparent background, with the logo inset rather than filling the frame. Expo's config plugin compiles to the same Android 12 splash API, so the circular mask applies to Expo apps too — which is why a logo that reaches the edges of splash-icon.png gets cropped after prebuild.
No. Full-bleed splash bitmaps had to be redrawn for every screen ratio, stretched on the ones you missed, and are ignored outright on Android 12+. The supported approach on every version is a background colour plus a centred logo, which is what this tool generates. The ZIP also includes a layer-list fallback for projects that cannot add the core-splashscreen dependency.
iOS caches launch screens aggressively, and a rebuild alone will keep showing the old one. Delete the app from the simulator or device and install it fresh. This is almost always the explanation when a new LaunchScreen.storyboard appears to have no effect.
On Android, put the dark colours in values-night/colors.xml and the dark artwork in drawable-night-* folders. On iOS, use an asset-catalog colour set with a dark appearance variant and reference it from the storyboard rather than hardcoding a hex. On Expo, add the dark key to the expo-splash-screen plugin config. Enabling dark mode variants here generates all three.
Something drawn from your own branding, and — more importantly — the same colour as the first screen the app renders, otherwise users see a flash between the two. This tool extracts the palette from your logo and derives a light and a dark background from its hue, desaturated so the artwork stays readable. It also warns you when a chosen colour sits too close to the logo, which is what happens if you set the background to the logo's dominant colour directly and the logo disappears.
Usually because the source file already has a wide transparent margin baked in, which then stacks with the splash safe zone. The trim option measures your logo from its actual opaque edges first, so the size percentage means what it says.
Yes. The Expo folder contains splash-icon.png plus the app.json plugin block for SDK 50 and later, and a legacy expo.splash block for SDK 49 and earlier. The Android and iOS folders are plain native resources, so they work in bare React Native and in native Android or iOS projects with no React Native at all.
No. Every resize runs in your browser through the HTML5 Canvas API. The logo never leaves your device, nothing is stored or logged, and the tool keeps working with the network disconnected.
The app icon generator takes the same master logo and exports Xcode AppIcon.appiconset with Contents.json, every Android mipmap density, adaptive foregrounds and the Google Play 512px listing icon.