agentsclimarketplace

Svelte expert

Skill Akayashuu/agent-skills/skills/svelte-expert

Use when writing, reviewing, or refactoring Svelte 5 components with runes — reaching for $state, $derived, $effect, $props, $bindable, snippets, stores, or shared reactive state in SvelteKit, or migrating legacy $:/export let code.From its SKILL.md

Install
npx -y skills add Akayashuu/agent-skills --skill svelte-expert

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.9 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it

Svelte Expert

Overview

Svelte 5 replaces compiler-magic reactivity with explicit runes. The mental model is closer to fine-grained signals than to Svelte 4. Most "outdated" code uses $:, export let, and writable stores for local state — all now legacy. Reach for $effect rarely: it is for side effects, not for computing values (same smell as misused React effects).

Quick Reference

GoalDoAvoid
Reactive local statelet x = $state(0)top-level let (no longer reactive)
Computed value$derived(a + b) / $derived.by(() => …)$: reactive statements
Component inputslet { x } = $props() + TS typeexport let x
Two-way bindinglet { v = $bindable() } = $props()manual event dispatch round-trips
Side effect / sync external$effect(() => …)using it to derive state
Effect cleanupreturn () => teardown()leaking listeners/timers
Shared reactive staterune state in .svelte.ts modulewritable store for everything
Cross-cutting / RxJS interopwritable/readable storereinventing with runes
List rendering{#each items as it (it.id)}unkeyed {#each}
Reusable markup{#snippet} / {@render}slots (legacy)

Core Patterns

State + derived — never compute with $effect:

<script lang="ts">
  // ❌ legacy + effect-as-derivation: extra render, stale risk
  // export let items: Item[];
  // $: total = items.reduce((n, i) => n + i.price, 0);
  // let count = 0;
  // $effect(() => { count = items.length; }); // wrong: derive, don't sync

  // ✅ runes
  let { items }: { items: Item[] } = $props();
  const total = $derived(items.reduce((n, i) => n + i.price, 0));
  const count = $derived(items.length);
</script>

Runnable (state factory + $derived / $derived.by): examples/state-derived.svelte.ts

$props with types and $bindable — replaces export let:

<script lang="ts">
  let {
    value = $bindable(''),     // two-way: <Input bind:value/>
    placeholder = 'Search',    // plain prop with default
    onsubmit,                  // callback prop, not createEventDispatcher
  }: { value?: string; placeholder?: string; onsubmit?: (v: string) => void } = $props();
</script>

$effect only for external systems, with cleanup:

<script lang="ts">
  let { roomId }: { roomId: string } = $props();
  let messages = $state<Msg[]>([]);

  $effect(() => {
    const sock = connect(roomId);          // re-runs when roomId changes
    sock.on('msg', (m) => messages.push(m)); // deep proxy: mutate, don't reassign
    return () => sock.close();             // cleanup before re-run / unmount
  });
</script>

Use $effect.pre(() => …) (same API, runs before DOM updates) for the rare case of reading layout before a render — e.g. capturing scroll position for autoscroll.

Runnable ($effect cleanup + $effect.pre): examples/effect-cleanup.svelte.ts

Shared state — .svelte.ts module, not a store:

// counter.svelte.ts
let count = $state(0);              // private: can't export a reassigned $state directly
export const counter = {
  get value() { return count; },   // getter exposes the live reactive read
  inc() { count++; },
};
// any component: import { counter } — reactive across the app

The compiler wraps reactivity per file, so a directly exported primitive $state won't stay reactive when reassigned elsewhere. Export an object (mutate its fields) or a getter/function API. See shared.svelte.ts for both patterns.

Fine-grained reactivity: $state returns a deep proxy. Mutate in place (obj.field = x, arr.push(...)) — reassigning the whole object is unnecessary and loses fine-grained tracking. Use (item.id) keys in {#each} so Svelte moves DOM nodes instead of recreating and remounting them.

Common Mistakes

  • $: / export let in new code — Svelte 4 idioms; use $derived / $props.
  • $effect to derive state — causes extra passes and stale values; use $derived/$derived.by.
  • Effect-driven loops — an $effect that reads and writes the same $state loops infinitely. Prefer $derived; only if you must write state in an effect, read the looping dependency via untrack(() => …). Runnable: examples/derived-not-effect.svelte.ts.
  • Writable store for component-local state — use $state; reserve stores for cross-cutting concerns or external (RxJS) interop.
  • Reassigning whole objects — breaks fine-grained updates; mutate proxy fields directly.
  • Unkeyed {#each} — wrong DOM reuse on reorder; always provide (item.id).
  • createEventDispatcher / slots — replaced by callback props and snippets.

When NOT to over-engineer

A small leaf component with one prop and no derived state needs no ceremony — let { label } = $props() is the whole story. Don't build a .svelte.ts store for state one component owns. Don't wrap $derived around a value used once inline. Runes are cheap; reach for shared modules and $effect only when something actually crosses component boundaries or touches the outside world.

Sources

What ships with it: 4 files

5.5 KB alongside SKILL.md, 4 of them executable

Keep looking

Skills are one crate of 625,857. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.