Skip to main content

Loading and splash screens

GameProvider owns one deterministic startup sequence:

Game.init + preload content → loading screen → splash screens → game UI

Initialization and preloading run in parallel. The game UI is mounted only after both finish and the splash sequence completes.

Preload game content

Pass the assets needed for the first playable scene. Strings are inferred by extension; image resources wait for browser decoding, while other resources are fetched and fully consumed.

src/main.tsx
const preload = [
"/maps/world.webp",
"/audio/theme.ogg",
{
src: "/maps/world.webp",
type: "image",
srcSet: "/maps/world-640.webp 640w, /maps/world.webp 1280w",
sizes: "100vw",
},
] as const;

<GameProvider
options={gameOptions}
preload={preload}
preloadConcurrency={4}
>
<PassageController />
</GameProvider>;

The queue deduplicates source URLs, loads at most six resources concurrently by default, accepts an AbortSignal internally, and continues after individual asset failures. Progress counts completed resources, including failed resources, so a broken optional asset cannot trap the player on the loading screen.

Use a custom task when loading requires more than an HTTP request—for example, decoding Web Audio data:

const preload = [
{
id: "battle-music-buffer",
async load(signal: AbortSignal) {
const response = await fetch("/audio/battle.ogg", { signal });
const bytes = await response.arrayBuffer();
await audioContext.decodeAudioData(bytes);
},
},
];

For a core-only application, call the same API directly:

import { preloadContent } from "@react-text-game/core";

const result = await preloadContent(preload, {
concurrency: 4,
signal: abortController.signal,
onProgress: ({ completed, total, progress }) => {
console.log({ completed, total, percentage: progress * 100 });
},
});

console.log(result.failures);

Preload only resources required immediately or in the next likely scene. Eagerly requesting an entire game competes with critical page resources and wastes bandwidth. Use responsive srcSet and sizes for large images so the browser can select the right candidate. See the browser guidance for responsive image preloading, HTMLImageElement.decode(), and abortable work.

Configure the loading screen

The default loading screen is rendered whenever preload is non-empty. It shows the React Text Game logo, loading..., and an accessible progress bar.

<GameProvider
options={gameOptions}
preload={preload}
loadingScreen={{
backgroundImage: "/ui/loading-background.webp",
text: [
"Charting the world...",
"Waking the characters...",
"Preparing your story...",
],
textInterval: 1800,
progressTrackClassName: "h-1 bg-white/20",
progressBarClassName: "bg-amber-300",
progressBarStyle: { boxShadow: "0 0 16px #fcd34d" },
}}
>
<PassageController />
</GameProvider>

text accepts one string or an array. Array entries rotate with a fade animation. Style the container, logo, text, track, and indicator with class names or inline style objects.

Replace the complete loading screen through the component registry:

import type { LoadingScreenProps } from "@react-text-game/ui";

function MyLoadingScreen({ progress }: LoadingScreenProps) {
return (
<MyFullScreenLayout>
<MyProgress value={progress.progress} />
<span>{progress.completed} / {progress.total}</span>
</MyFullScreenLayout>
);
}

const components = { LoadingScreen: MyLoadingScreen };

<GameProvider
options={gameOptions}
components={components}
preload={preload}
>
<PassageController />
</GameProvider>;

Configure splash screens

In production, the built-in React Text Game splash is enabled by default. It lasts 1.5 seconds including fade-in and fade-out, and a click skips it immediately.

const splashScreens = [
{
id: "publisher",
content: <PublisherLogo />,
duration: 2500,
},
{
id: "legal",
content: <LegalNotice />,
duration: 4000,
isInterruptible: false,
className: "bg-slate-950 text-white",
},
];

<GameProvider
options={gameOptions}
splashScreens={splashScreens}
>
<PassageController />
</GameProvider>;

Durations are milliseconds and include both transitions. isInterruptible defaults to true. Interruptible screens use a semantic button, so pointer and keyboard activation both skip them.

OptionDefaultEffect
showSplashScreentrueEnables or disables the whole sequence
showSplashScreenOnDevfalseAllows the sequence when options.isDevMode is true
showRTGSplashScreentrueAdds the built-in React Text Game screen first
splashScreens[]Adds custom screens after the built-in screen

Disable the built-in screen and keep custom screens with showRTGSplashScreen={false}. Replace only its visual through components.RTGSplashScreen. Disable every splash with showSplashScreen={false}.

Loading text and splash transitions honor the operating-system prefers-reduced-motion setting. The default progress element also exposes the standard progressbar semantics.