Landing pages for local businesses that have to convert on the first scroll — shipped as three complete, clickable templates instead of a slide deck.
| Route | Template | Design language |
|---|---|---|
/ |
Pulso — the studio's own site | night + violet |
/demos/academia |
Forja Academia — gym / fitness | carbon + volt |
/demos/revolve |
REVOLVE — premium product page | obsidian + copper |
Three brands, one codebase. Each template owns a Tailwind v4 @theme token set in src/routes/layout.css, so palettes cannot leak between templates and nothing is copy-pasted.
- Svelte 5 runes end to end.
$state,$props,$derived,$effect— no legacy stores anywhere undersrc/lib. - Scroll-synced motion, not just scroll-triggered.
src/lib/motion.tsexports two actions:reveal()(IntersectionObserver → anime.js fade/translate) andparallax()(anime.jsonScroll→ transform).Story.sveltedrives an SVG ring'sstroke-dashoffsetstraight from scroll position. - 3D that never taxes the first paint.
src/lib/three/DeviceMorph.sveltedynamically imports the Threlte scene the first time its section intersects, so Three.js lands in its own Vite chunk behind a poster image. - Reduced motion is a real path, not an afterthought.
[data-animate]elements start hidden and are revealed by the anime.js timeline; underprefers-reduced-motion— and with JS disabled, thanks to SSR — the content is simply there. - No contact backend, deliberately. Every CTA is a WhatsApp deep link built by
waLink()insrc/lib/site.ts, because that is where these customers actually reply.
src/
routes/
+page.svelte → Pulso agency site
demos/academia/ → Forja gym template
demos/revolve/ → REVOLVE product template
layout.css → three @theme token sets, keyframes, grain utility
lib/
agency/ → 11 components (Hero, Trust, Niches, Process, Pricing, FAQ…)
academia/ → 13 components (Modalidades, Planos, Galeria, Local…)
components/ → 9 generic product components (Marquee, Story, Specs…)
three/ → Threlte/Three.js layer, lazy-loaded
motion.ts → reveal() + parallax() actions
site.ts → WhatsApp contact config
Svelte 5 · SvelteKit · TypeScript · Tailwind CSS v4 · anime.js 4 · Three.js + Threlte · Vitest (browser tests via Playwright) · @sveltejs/adapter-vercel (Node 22)
bun install
bun run dev # Vite dev server with HMR
bun run test # Vitest — unit + browser component tests
bun run build # Vercel adapter outputNo environment variables required. The WhatsApp number lives in src/lib/site.ts.
All three templates are finished end to end — copy, imagery, motion and responsive behaviour. No TODOs in the tree. Content is intentionally hardcoded in components; there is no CMS, analytics or form backend.