diff --git a/packages/onboarding-ui/src/pages/LoaderPage/LoaderPage.spec.tsx b/packages/onboarding-ui/src/pages/LoaderPage/LoaderPage.spec.tsx
new file mode 100644
index 0000000000..ea0ea30c62
--- /dev/null
+++ b/packages/onboarding-ui/src/pages/LoaderPage/LoaderPage.spec.tsx
@@ -0,0 +1,21 @@
+import ReactDOM from 'react-dom';
+
+import LoaderPage from './LoaderPage';
+
+const subtitles = [
+ 'Bringing rocket to launch position',
+ 'Loading rocket propellant',
+ 'Performing final go/no go poll with flight crew',
+ 'All systems nominal, switching to internal computer',
+ 'Beginning countdown, 5...4...3...2...1',
+ 'Transitioning to liftoff',
+];
+
+it('renders without crashing', () => {
+ const div = document.createElement('div');
+ ReactDOM.render(
+ ,
+ div
+ );
+ ReactDOM.unmountComponentAtNode(div);
+});
diff --git a/packages/onboarding-ui/src/pages/LoaderPage/LoaderPage.stories.tsx b/packages/onboarding-ui/src/pages/LoaderPage/LoaderPage.stories.tsx
new file mode 100644
index 0000000000..e1262d4b1b
--- /dev/null
+++ b/packages/onboarding-ui/src/pages/LoaderPage/LoaderPage.stories.tsx
@@ -0,0 +1,33 @@
+import type { Story, Meta } from '@storybook/react';
+import type { ComponentProps } from 'react';
+
+import LoaderPage from './LoaderPage';
+
+const subtitles = [
+ 'Bringing rocket to launch position1 🚀',
+ 'Loading rocket propellant 🚀',
+ 'Performing final go/no go poll with flight crew 🚀',
+ 'All systems nominal, switching to internal computer 🚀',
+ 'Beginning countdown, 5...4...3...2...1 🚀',
+ 'Transitioning to liftoff 🚀',
+];
+
+type Args = ComponentProps;
+
+export default {
+ title: 'pages/LoaderPage',
+ component: LoaderPage,
+ parameters: {
+ actions: { argTypesRegex: '^on.*' },
+ layout: 'fullscreen',
+ },
+ args: {
+ title: 'Launching Kapai...',
+ subtitles,
+ isReady: false,
+ loadingSeconds: 15,
+ },
+} as Meta;
+
+export const _LoaderPage: Story = (args) => ;
+_LoaderPage.storyName = 'LoaderPage';
diff --git a/packages/onboarding-ui/src/pages/LoaderPage/LoaderPage.tsx b/packages/onboarding-ui/src/pages/LoaderPage/LoaderPage.tsx
new file mode 100644
index 0000000000..22f9999270
--- /dev/null
+++ b/packages/onboarding-ui/src/pages/LoaderPage/LoaderPage.tsx
@@ -0,0 +1,70 @@
+import { Box, Margins, ProgressBar } from '@rocket.chat/fuselage';
+import type { ReactElement } from 'react';
+import { useEffect, useState } from 'react';
+
+import BackgroundLayer from '../../common/BackgroundLayer';
+import { OnboardingLogo } from '../../common/OnboardingLogo';
+
+type LoaderPageProps = {
+ title: string;
+ subtitles: string[];
+ isReady: boolean;
+ loadingSeconds?: number;
+};
+
+const LoaderPage = ({
+ title,
+ subtitles,
+ isReady = false,
+ loadingSeconds = 90,
+}: LoaderPageProps): ReactElement => {
+ const timeFraction = 100 / subtitles.length;
+
+ const [percentage, setPercentage] = useState(0);
+ const [subtitleIndex, setSubtitleIndex] = useState(0);
+
+ const progressHandler = () => {
+ const interval = (loadingSeconds * 1000) / 100;
+ setInterval(() => {
+ setPercentage((prev) => (prev === 99 ? 99 : prev + 1));
+ }, interval);
+ };
+
+ useEffect(() => {
+ if (isReady) setPercentage(100);
+ else progressHandler();
+ }, [isReady]);
+
+ useEffect(() => {
+ // Change subtitle according to percentage
+ const index = Math.floor(percentage / timeFraction);
+ if (index !== subtitleIndex) setSubtitleIndex(index);
+ }, [percentage]);
+
+ return (
+
+
+
+
+
+ {title}
+
+ {subtitles[subtitleIndex]}
+
+
+
+
+
+ );
+};
+
+export default LoaderPage;
diff --git a/packages/onboarding-ui/src/pages/LoaderPage/index.ts b/packages/onboarding-ui/src/pages/LoaderPage/index.ts
new file mode 100644
index 0000000000..7445f87f72
--- /dev/null
+++ b/packages/onboarding-ui/src/pages/LoaderPage/index.ts
@@ -0,0 +1 @@
+export { default } from './LoaderPage';