Español · Quick start: QUICK_START.md
Starter template for modern websites with SvelteKit 2 + Svelte 5 + TypeScript + Tailwind CSS v4 and shadcn-svelte-style UI (code lives in your repo, not an opaque package).
The home uses Material/Stitch tokens (src/lib/styles/stitch-m3.css), ES/EN i18n on the landing, and centralized SEO via $seo.
npm install # first time only
npm run dev # dev server
Open http://localhost:5173. You do not need a .env file to get started.
Requirements: Node.js 22+ (see package.json → engines).
/ — Landing (hero, sample terminal, features, steps, CTAs; copy in src/lib/i18n/*.json under home.*)/components — UI gallery and template demos (about, pricing, faq, SSR with load(), blog, form). Content in src/lib/components/demos/*.svelte; SSR data in src/routes/components/+page.ts./components) — legacy links or bookmarks: /about, /pricing, /faq, /blog, /blog/primer-post, /ssr-demo, /contacto (form action in src/routes/components/+page.server.ts).Base UI (src/lib/components/ui/, shadcn-svelte pattern + bits-ui): Button, Card, Dialog, Input, Textarea, Label, Skeleton, Spinner, Sonner (toast).
Project (src/lib/components/): Footer, Heading, Container, Section, Grid, CopyButton, Newsletter, AiPrompt, JsonLd, CookieConsent, BlogLayout, LoadingBlock, demos under demos/, etc. (optional marketing blocks like Hero are not all wired on the current home).
/sitemap.xml (with hreflang ES/EN), /robots.txt (AI crawlers: GPTBot, Claude, Perplexity, Google-Extended, CCBot…), /llms.txt + /llms-full.txt (llmstxt.org standard), Markdown twins per page (/index.md, /ruta.md) with HTTP content negotiation (Accept: text/markdown), complete Open Graph + Twitter Cards, canonical URL auto-derived, dynamic <html lang> via SSR cookie, and JSON-LD that ships Organization + WebSite (SearchAction) + BreadcrumbList + FAQPage + HowTo + SoftwareApplication out of the box. Just call setSeo({...}) in your +page.svelte.<Toaster /> in layout) + toast() from $lib/stores/toast (also <ToastContainer /> in layout)/api/og?title=Texthooks.server.ts; markdown twins get Vary: Accept, X-AEO-Version, X-Markdown-Tokens, X-Robots-Tag: noindexIn this repo: sanity/ folder (schemas, seeds), sanity.config.ts / sanity.cli.ts, and server code under src/lib/server/sanity/ (client with @sanity/client, sample GROQ queries, types). The sanity package is in devDependencies so you can run Studio; @sanity/client and @sanity/image-url are in dependencies for SSR on the app.
What the template does not do by default: no route uses GROQ out of the box. Without Sanity env vars the site still runs; when you want CMS data, call getSanityServerClient() from a load or +page.server.ts.
Typical env vars (.env, never commit secrets): SANITY_PROJECT_ID, SANITY_DATASET; optional SANITY_READ_TOKEN for drafts or private datasets. sanity.config.ts can also use SANITY_STUDIO_PROJECT_ID / SANITY_STUDIO_DATASET if you want Studio separate from runtime.
Run Studio: npm run studio (Sanity CLI; different port from Vite). Create or link a project at sanity.io and align projectId and dataset with your environment.
AGENTS.md — How ChatGPT, Claude, Copilot should work in this repoPROMPTS.md — Copy-paste snippets for AI promptsDESIGN_TO_CURSOR.md — Stitch / Lovable → this template (tokens, checklist, base prompt)Optional (recommended): install extra skills detected for your stack (Cursor, Claude Code, etc.):
npx autoskills
See INSTRUCTIONS.txt (section “Using AI to help you”). Spanish step-by-step: INSTRUCCIONES.txt.
| Command | Description |
|---|---|
npm run dev |
Development server |
npm run build |
Production build |
npm run preview |
Preview production build |
npm run check |
Type-check + svelte-check (0 errors, 0 warnings) |
npm run lint |
ESLint + Prettier |
npm run format |
Format everything |
npm run test |
Tests |
npm run new:page name |
Scaffold a page |
npm run studio |
Sanity Studio (optional CMS in dev) |
sanity/ → Schemas, seeds, Studio (optional; see Sanity section)
sanity.config.ts
sanity.cli.ts
src/
routes/
+page.svelte → Home
+layout.svelte → Global layout (header, nav, footer, toasts, cookies, dark mode)
+error.svelte → 404/500
blog/ → +page.ts redirects to gallery; primer-post/ → demo post anchor
contacto/ → Redirect to form anchor on /components
about/ pricing/ faq/ ssr-demo/ → +page.ts only (307 → /components#…)
components/ → UI gallery + demos (SSR load, contact form action)
api/
og/+server.ts → Dynamic OG image
lib/
styles/stitch-m3.css → M3/Stitch tokens + utilities (text-h1, font-code…)
site-config.ts → Site name, URL, social links
components/
ui/ → shadcn-svelte + base components (Button, Card, Input…)
*.svelte → Project components
stores/
toast.ts → Toast notifications
actions/
clickOutside.ts → Svelte action
i18n/ → ES/EN translations
seo.ts → SEO store
aeo/ → Markdown twins, Accept negotiation, builders from i18n
site-pages.ts → Central page registry (sitemap, llms, AEO twins)
reveal.ts → Scroll animations
utils.ts → cn(), types
server/
supabase/ → Supabase client (optional)
sanity/ → GROQ client + types (optional)
app.css → Global CSS + Tailwind v4 + theme variables
hooks.server.ts → Security headers, CSP, AEO content negotiation
static/
logos/ → Brand SVGs (reference)
manifest.json → Web app manifest
favicon.svg
SEO/GEO/AEO routes (
robots.txt,sitemap.xml,llms.txt,llms-full.txt,*.mdtwins) are dynamic SvelteKit endpoints undersrc/routes/, fed fromsrc/lib/site-pages.ts+ i18n. To add a page to all of them at once, append an entry tositePagesand register a builder insrc/lib/aeo/(see AEO below).
The template is wired so that calling setSeo({...}) in a page is enough — every other tag, schema and crawler file is auto-generated.
// src/routes/mi-pagina/+page.svelte
import { setSeo } from '$lib/seo';
setSeo({
title: 'Mi página',
description: 'Resumen en una frase.',
schemaType: 'FAQPage',
dateModified: new Date().toISOString(),
faq: [{ question: '¿Qué es X?', answer: 'X es...' }],
howto: [{ name: 'Paso 1', text: 'Haz Y' }]
});
That single call updates:
| Output | What it does |
|---|---|
<title>, description, keywords, author, canonical |
Standard SEO tags |
| Open Graph + Twitter Cards | Social previews |
hreflang ES/EN/x-default |
International SEO |
JSON-LD WebPage / Article / FAQPage / HowTo / SoftwareApplication |
Rich results in Google + citations in ChatGPT / Perplexity / Gemini |
BreadcrumbList |
Auto-derived from URL |
Organization + WebSite with SearchAction |
Sitewide schema |
And from src/lib/site-pages.ts the template auto-generates:
/sitemap.xml with hreflang/llms.txt (Markdown index, llmstxt.org)/llms-full.txt (full content for LLM ingestion)/robots.txt (allow-list for OpenAI, Anthropic, Google, Perplexity, CCBot, Meta, Cohere)To add a new page to all of them, append one entry to sitePages in src/lib/site-pages.ts.
Besides GEO (llms.txt, structured data), each indexable route gets a Markdown twin so AI agents (ChatGPT, Claude, Perplexity, etc.) can ingest clean text without parsing HTML. The implementation follows common conventions (acceptmarkdown.com, Dualmark AEO spec).
| Mechanism | Behavior |
|---|---|
| Content negotiation | GET / with Accept: text/markdown → same URL, markdown body |
| AI bot User-Agents | GPTBot, ClaudeBot, PerplexityBot, Google-Extended, etc. → markdown twin on the canonical URL |
| Sibling URLs | /index.md (home), /components.md, … |
| HTML discovery | <link rel="alternate" type="text/markdown" href="…"> in layout + Link HTTP header |
| Twin headers | Content-Type: text/markdown, Vary: Accept, X-AEO-Version: 1.0, X-Markdown-Tokens, X-Robots-Tag: noindex |
| Source of truth | i18n (src/lib/i18n/*.json) via builders in src/lib/aeo/builders/ — no duplicate hand-written .md files per locale |
| Sitemap | HTML URLs + .md twins in /sitemap.xml |
setSeo({...}) in +page.svelte (inside $effect with $locale).sitePages in src/lib/site-pages.ts.buildYourPageMarkdown(locale, baseUrl) in src/lib/aeo/builders/ and register it in src/lib/aeo/registry.ts.src/routes/your-slug.md/+server.ts that calls serveMarkdownTwin (home uses index.md).Full checklist for Cursor/agents: AGENTS.md → section SEO + GEO + AEO.
curl.exe -sI -H "Accept: text/markdown" http://localhost:5173/
curl.exe -sI http://localhost:5173/index.md
You should see content-type: text/markdown and the x-aeo-* headers. Tools like aeochecker.xyz must hit your deployed URL after git push — production does not update until you redeploy.
src/lib/site-config.tsSite name, URL, social links, author defaults used by src/lib/seo.ts.
src/lib/i18n/es.json and en.jsonLanding copy (home.*), navigation (layout.nav.*), footer, and other keys. The document title comes from the seo store (<title>{$seo.title}</title> in the layout); each route can call setSeo({ title, description, ... }).
src/app.css and src/lib/styles/stitch-m3.cssTheme tokens (--primary, --background, …) and Stitch typography utilities. Legacy variables (--text-main, --bg-soft) are aligned with --foreground / --muted.
import { mode, toggleMode } from 'mode-watcher';
import { Moon, Sun } from 'lucide-svelte';
<Button variant="ghost" size="icon" onclick={toggleMode}>
{#if mode.current === 'dark'} <Moon /> {:else} <Sun /> {/if}
</Button>
Vercel and Netlify. Push to GitHub, connect the repo, done.
Free for personal and commercial use.