Vite

Plain Svelte + Vite, no router. Same primitives, same tokens — fewer moving parts for a prototype scene.

1. Scaffold

Terminal
pnpm create vite@latest my-prototype -- --template svelte-ts
cd my-prototype
pnpm install

2. Install dependencies

Terminal
pnpm add bits-ui remixicon tailwind-variants tailwind-merge clsx
pnpm add -D @fontsource-variable/geist @fontsource-variable/geist-mono tailwindcss @tailwindcss/vite tw-animate-css

3. Wire Tailwind v4

Vite needs the @tailwindcss/vite plugin; there’s no PostCSS step.

vite.config.ts
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
	plugins: [tailwindcss(), svelte()]
});

4. Tokens and fonts

Copy theme.css and motion.css from Bloom’s src/lib/tokens/ into your project’s src/ tree and import them from your global stylesheet.

src/app.css
@import 'tailwindcss';
@import 'tw-animate-css';
@import 'remixicon/fonts/remixicon.css';

@import '@fontsource-variable/geist';
@import '@fontsource-variable/geist-mono';

@import './tokens/theme.css';
@import './tokens/motion.css';

@custom-variant dark ([data-theme='dark'] &);

5. Path aliases (optional)

SvelteKit ships $lib for free; Vite doesn’t. If you want to mirror Bloom’s imports verbatim, add an alias to vite.config.ts pointing $lib at src/lib. Otherwise use relative imports — the components don’t care.

Caveats

  • No file-based router means you roll your own navigation. Good for a single-screen prototype; friction for anything multi-route.
  • @sveltejs/kit-specific features ($app/navigation, $app/stores, server loaders) aren’t available. Bloom’s docs primitives use afterNavigate — if you lift them out, replace that with a plain store subscription or a location watcher.