Skip to content
System

Splash Screen

The screen an app shows before it has anything else to show — six looks, seven indicators, eight ways to leave, and no wiring for the common case.

Walkthrough

1. Basic

The whole of it: a splash over the app, and the app behind it once it goes. In a real layout you would leave open alone — the splash waits for the page to load and takes itself off. Here it is bound to a timer so you can watch it again.

Dashboard

The app behind the splash.

Acme

Getting your workspace ready.

Loading your workspace

<script lang="ts">	import { Button, SplashScreen, Text } from 'omaris';​	let booting = $state(true);​	$effect(() => {		if (!booting) return;		const timer = setTimeout(() => (booting = false), 1800);		return () => clearTimeout(timer);	});</script>​<div class="relative h-full w-full overflow-hidden rounded-shape-lg border border-border">	<div class="flex h-full flex-col items-start gap-3 p-6">		<Text variant="headline-sm" as="h2">Dashboard</Text>		<Text tone="muted">The app behind the splash.</Text>		<Button size="xs" onclick={() => (booting = true)}>Boot again</Button>	</div>​	<SplashScreen		bind:open={booting}		inline		title="Acme"		description="Getting your workspace ready."		pattern="gradient"		message="Loading your workspace"	>		{#snippet logo()}			...		{/snippet}	</SplashScreen></div>

2. Looks

Two decisions, taken separately: variant is the colour the screen is, pattern is the decorative layer over it. Six by seven, and every pairing is one word each.

grid

dots

aurora

spotlight

mesh

gradient

<script lang="ts">	import { SplashScreen, type SplashScreenPattern, type SplashScreenVariant } from 'omaris';​	const looks: { variant: SplashScreenVariant; pattern: SplashScreenPattern }[] = [		{ variant: 'background', pattern: 'grid' },		{ variant: 'surface', pattern: 'dots' },		{ variant: 'primary', pattern: 'aurora' },		{ variant: 'inverse', pattern: 'spotlight' },		{ variant: 'background', pattern: 'mesh' },		{ variant: 'surface', pattern: 'gradient' }	];</script>​<div class="grid w-full gap-4 sm:grid-cols-2 lg:grid-cols-3">	{#each looks as look (look.variant + look.pattern)}		<div class="relative h-48 overflow-hidden rounded-shape-lg border border-border">			<SplashScreen				open				inline				size="sm"				variant={look.variant}				pattern={look.pattern}				title={look.pattern}				indicator="dots"			/>		</div>	{/each}</div>

3. Indicators

Seven ways to say "working on it". bar is the only one that can also say how far along it is; the rest are honest about knowing nothing.

spinner

ring

dots

bar

wave

orbit

pulse

<script lang="ts">	import { SplashScreen, type SplashScreenIndicator } from 'omaris';​	const indicators: SplashScreenIndicator[] = [		'spinner',		'ring',		'dots',		'bar',		'wave',		'orbit',		'pulse'	];</script>​<div class="grid w-full gap-4 sm:grid-cols-2 lg:grid-cols-4">	{#each indicators as indicator (indicator)}		<div class="relative h-40 overflow-hidden rounded-shape-lg border border-border">			<SplashScreen open inline size="sm" {indicator} message={indicator} />		</div>	{/each}</div>

4. Exits

The part anyone remembers. Press one and watch it go: iris opens a hole in the middle and the app is behind it, rise takes the whole screen up like a curtain.

the app

fade

the app

scale

the app

zoom

the app

rise

the app

fall

the app

swipe

the app

blur

the app

iris

<script lang="ts">	import { Button, SplashScreen, Text, type SplashScreenExit } from 'omaris';​	const exits: SplashScreenExit[] = [		'fade',		'scale',		'zoom',		'rise',		'fall',		'swipe',		'blur',		'iris'	];​	/** Which are currently up. Replaying one drops it and puts it back a frame later. */	let up = $state<Record<string, boolean>>(Object.fromEntries(exits.map((e) => [e, true])));​	function replay(exit: string) {		up[exit] = false;		setTimeout(() => (up[exit] = true), 700);	}</script>​<div class="grid w-full gap-4 sm:grid-cols-2 lg:grid-cols-4">	{#each exits as exit (exit)}		<div class="flex flex-col gap-2">			<div class="relative h-40 overflow-hidden rounded-shape-lg border border-border">				<div class="grid h-full place-items-center">					<Text variant="label-sm" tone="muted">the app</Text>				</div>				<SplashScreen					open={up[exit]}					inline					{exit}					size="sm"					pattern="gradient"					title={exit}					indicator="none"					minDuration={0}					duration={700}				/>			</div>			<Button size="xs" variant="outlined" onclick={() => replay(exit)}>Play {exit}</Button>		</div>	{/each}</div>

5. Boot sequence

createSplash carries open, progress and message together, so the screen says what the app is actually doing. run walks the steps, weights the bar by how slow each one is, and takes the splash down at the end — including when a step throws.

Workspace

Loaded.

Acme

v2.4.0
<script lang="ts">	import { Button, createSplash, SplashScreen, Text } from 'omaris';​	// `open: false` because the app is already up here; a real one starts up.	const splash = createSplash({ open: false });​	const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));​	const boot = () =>		splash.run([			{ label: 'Signing you in', run: () => wait(700) },			{ label: 'Loading your workspace', weight: 2, run: () => wait(1200) },			{ label: 'Almost there', run: () => wait(500) }		]);</script>​<div class="relative h-full w-full overflow-hidden rounded-shape-lg border border-border">	<div class="flex h-full flex-col items-start gap-3 p-6">		<Text variant="headline-sm" as="h2">Workspace</Text>		<Text tone="muted">Loaded.</Text>		<Button size="xs" onclick={boot}>Run the boot sequence</Button>	</div>​	<SplashScreen		{splash}		inline		title="Acme"		pattern="aurora"		indicator="bar"		percent		halo		exit="iris"	>		{#snippet logo()}			...		{/snippet}		{#snippet footer()}			<Text variant="label-sm">v2.4.0</Text>		{/snippet}	</SplashScreen></div>

6. Overridden

Every part is reachable. This one is left-aligned, bottom-anchored, has a display-sized title, a tertiary indicator and a footer of its own — none of which is a prop the component had to invent.

Ledger

Reconciling accounts

Built by Acme · v2.4.0
<script lang="ts">	import { Button, SplashScreen, Text } from 'omaris';​	let open = $state(true);</script>​<div class="flex h-full w-full flex-col gap-3">	<div class="relative min-h-0 flex-1 overflow-hidden rounded-shape-lg border border-border">		<SplashScreen			{open}			inline			variant="inverse"			pattern="grid"			align="bottom"			enter="reveal"			indicator="wave"			exit="rise"			title="Ledger"			message="Reconciling accounts"			classes={{				content: 'w-full max-w-none items-start px-10 text-start',				title: 'text-display-sm',				indicator: 'text-tertiary',				message: 'opacity-60',				footer: 'items-start px-10 text-start'			}}		>			{#snippet footer()}				<Text variant="label-sm">Built by Acme · v2.4.0</Text>			{/snippet}		</SplashScreen>	</div>​	<Button size="xs" variant="outlined" class="self-start" onclick={() => (open = !open)}>		{open ? 'Hide' : 'Show'}	</Button></div>