---
trigger: glob
globs: src/**/*.svelte,src/**/*.svelte.ts
---

# Svelte 5 (runes)

- Use runes only: `let count = $state(0)`, `const doubled = $derived(count * 2)`, `$derived.by(() => ...)` for multi-line.
- Props: `let { title, items = [], onselect } = $props();` with a `Props` type. Two-way props with `$bindable()`.
- `$effect` only for side effects touching the outside world (DOM APIs, subscriptions), with a returned cleanup. Never use it to sync one state into another; use `$derived`.
- Events are props: `onclick={handle}`, not `on:click`. Component events are callback props, not `createEventDispatcher`.
- Content via snippets: `{#snippet row(item)}...{/snippet}` and `{@render children?.()}`, not `<slot>`.
- Shared reactive state in `.svelte.ts` modules exporting `$state` objects or classes with `$state` fields.
- Keyed each blocks: `{#each items as item (item.id)}`.
- In SvelteKit, load data in `+page.ts`/`+page.server.ts` and read it from `let { data } = $props()`; mutations through form actions with `use:enhance`.

## Don't
- Don't use `export let`, `$:` reactive statements, or stores for local state in new code.

## Done when
`npx svelte-check` and `npm run test` pass.
