web-framework-svelte
Svelte 5のRunesという新しい仕組みを使って、状態管理やデータの加工、イベント処理などを効率的に行い、より使いやすいウェブサイトやアプリケーションを開発するSkill。
📜 元の英語説明(参考)
Svelte 5 Runes reactivity - $state, $derived, $effect, $props, $bindable, components, snippets, event handling, context API
🇯🇵 日本人クリエイター向け解説
Svelte 5のRunesという新しい仕組みを使って、状態管理やデータの加工、イベント処理などを効率的に行い、より使いやすいウェブサイトやアプリケーションを開発するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o web-framework-svelte.zip https://jpskill.com/download/10285.zip && unzip -o web-framework-svelte.zip && rm web-framework-svelte.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/10285.zip -OutFile "$d\web-framework-svelte.zip"; Expand-Archive "$d\web-framework-svelte.zip" -DestinationPath $d -Force; ri "$d\web-framework-svelte.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
web-framework-svelte.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
web-framework-svelteフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Svelte 5 のパターン
クイックガイド: Svelte 5 では、明示的なリアクティビティのために Runes を使用します。リアクティブな変数には
$state、計算された値には$derived、エスケープハッチとしてのみ$effectを使用します。スロットの代わりにスニペットを使用します。イベントディスパッチャーの代わりにコールバックプロップを使用します。コンポーネントを小さく、構成可能に保ちます。
<critical_requirements>
重要: この Skill を使用する前に
すべてのコードは、CLAUDE.md のプロジェクト規約に従う必要があります (kebab-case、名前付きエクスポート、インポート順序、
import type、名前付き定数)
(Svelte 5 の Runes 構文を使用する必要があります — export let、$:, ストアのような Svelte 4 のパターンは使用しないでください)
(計算された値には $derived を使用する必要があります — 状態を同期するために $effect を使用しないでください)
(スロット (<slot>) の代わりにスニペット ({#snippet} / {@render}) を使用する必要があります)
(createEventDispatcher の代わりにコールバックプロップ (onclick, onsomething) を使用する必要があります)
(変更ではなく置き換えられる大きなオブジェクト/配列には $state.raw() を使用する必要があります)
(生の setContext/getContext と文字列キーの代わりに、型安全なコンテキストには createContext を使用する必要があります)
</critical_requirements>
自動検出: Svelte 5, Runes, $state, $derived, $effect, $props, $bindable, $inspect, .svelte, snippet, @render, createContext, getContext, setContext, $state.raw, $state.eager, $derived.by, $effect.pre, ClassValue
いつ使用するか:
- Runes リアクティビティを使用して Svelte 5 コンポーネントを構築する場合
$stateでコンポーネントの状態を管理し、$derivedで計算された値を管理する場合- スニペット (スロットの代替) で再利用可能なマークアップを作成する場合
- ネイティブのイベント属性とコールバックプロップでイベントを処理する場合
- コンテキスト API でコンポーネント間で状態を共有する場合
$bindableプロップで双方向バインディングを行う場合
カバーする主なパターン:
- Runes:
$state,$derived,$effect,$props,$bindable,$inspect - スニペットと
{@render}を使用したコンポーネント構成 - ネイティブ属性とコールバックプロップを使用したイベント処理
- 型安全なコンポーネント間状態のための
createContextを使用したコンテキスト API $stateフィールドを使用したクラスベースのリアクティブな状態- 深いリアクティビティと浅いリアクティビティ (
$state対$state.raw)
いつ使用しないか:
- メタフレームワーク固有のパターン (ルーティング、ロード関数、フォームアクション) — 対応するメタフレームワークの Skill を使用してください
- Svelte 4 のパターン (
export let,$:, リアクティブステートメント,<slot>,createEventDispatcher) - サーバーサイドロジック (メタフレームワークのサーバーフックとルートを使用してください)
詳細なリソース:
- 意思決定フレームワークとアンチパターンについては、reference.md を参照してください
Runes とリアクティビティ:
- examples/core.md -
$state,$derived,$effect,$props,$bindable, コンポーネントパターン
コンポーネントパターン:
- examples/snippets.md - スニペットブロック,
{@render}, スニペットをプロップとして渡す, スロットの置き換え - examples/events.md - イベント処理, コールバックプロップによるコンポーネントイベント, イベント修飾子
高度な内容:
- examples/advanced.md -
$inspect, コンテキスト API,$state.raw,$state.eager, クラスベースの状態, 共有状態モジュール
<philosophy>
Philosophy
Svelte 5 では、Svelte に明示的できめ細かいリアクティビティをもたらす一連のプリミティブである Runes が導入されました。Svelte 4 のコンパイラマジック ($:, export let) とは異なり、Runes はリアクティビティを .svelte ファイル、.ts ファイル、およびクラス定義全体で可視化し、移植可能にします。
コア原則:
- 明示的なリアクティビティ — Runes (
$state,$derived,$effect) は、リアクティブな宣言を可視化します。隠れたコンパイラ変換はありません。 - エフェクトよりも派生 —
$effectではなく$derivedで値を計算します。エフェクトはエスケープハッチであり、主要なツールではありません。 - デフォルトで深いリアクティビティ —
$stateは、オブジェクト/配列に対して深いリアクティブプロキシを作成します。変更は自動的に追跡されます。 - スニペットはスロットを置き換える —
{#snippet}ブロックは、<slot>要素よりも強力で、型付けされ、構成可能です。 - コールバックプロップはイベントディスパッチャーを置き換える —
createEventDispatcherを使用する代わりに、onsomethingコールバックプロップを渡します。 - コンパイル時の最適化 — Svelte はコンポーネントを効率的な命令型コードにコンパイルします。実行時に仮想 DOM の差分処理は行いません。
Svelte 5 Runes をいつ使用するか:
- すべての新しい Svelte コンポーネント (Runes は Svelte 5 のデフォルトです)
.svelte.tsまたは.svelte.jsファイル内のリアクティブな状態- リアクティブなフィールドを持つクラスベースの状態
- リアクティブな状態に依存する計算された値
いつ使用しないか:
- 非リアクティブな定数 (プレーンな
constまたはletを使用) - リアクティビティを必要としないサーバーサイドコード
- メタフレームワークの懸念事項 (ルーティング、ロード関数、サーバーフック) — 対応するメタフレームワークの Skill を使用してください
- Svelte 4 のパターン —
export let,$:, コンポーネントの状態のためのストア,<slot>,createEventDispatcher
</philosophy>
<patterns>
コアパターン
パターン 1: $state を使用したリアクティブな状態
$state を使用してリアクティブな変数を宣言します。$state 変数への更新は、UI の再レンダリングを自動的にトリガーします。
<!-- counter.svelte -->
<script lang="ts">
let count = $state(0);
const STEP = 5;
function increment() {
count += 1;
}
function incrementByStep() {
count += STEP;
}
</script>
<button onclick={increment}>
Count: {count}
</button>
<button onclick={incrementByStep}>
+{STEP}
</button>
良い理由: 明示的なリアクティブ宣言、マジックナンバーの名前付き定数、プレーンな関数イベントハンドラー
<!-- 悪い例: Svelte 4 スタイル -->
<script>
let count = 0; // Svelte 5 モードでは明示的にリアクティブではありません
$: doubled = count * 2; // Svelte 4 のリアクティブステートメント
</script>
悪い理由: $ は Svelte 5 で非推奨の Svelte 4 構文であり、暗黙的なリアクティビティは紛らわしく、移植できません
深いリアクティビティ
$state はオブジェクトと配列に対して深いプロキシを作成します — 変更は自動的に追跡されます:
<script lang="ts">
interface Todo {
done: boolean;
text: string;
}
let todos = $state<Todo[]>([
{ done: false, text: 'Learn Svelte 5'
(原文がここで切り詰められています) 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Svelte 5 Patterns
Quick Guide: Svelte 5 uses Runes for explicit reactivity. Use
$statefor reactive variables,$derivedfor computed values,$effectonly as an escape hatch. Use snippets instead of slots. Use callback props instead of event dispatchers. Keep components small and composable.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use Svelte 5 Runes syntax — NOT Svelte 4 patterns like export let, $:, or stores for component state)
(You MUST use $derived for computed values — NEVER use $effect to synchronize state)
(You MUST use snippets ({#snippet} / {@render}) instead of slots (<slot>))
(You MUST use callback props (onclick, onsomething) instead of createEventDispatcher)
(You MUST use $state.raw() for large objects/arrays that are replaced, not mutated)
(You MUST use createContext for type-safe context instead of raw setContext/getContext with string keys)
</critical_requirements>
Auto-detection: Svelte 5, Runes, $state, $derived, $effect, $props, $bindable, $inspect, .svelte, snippet, @render, createContext, getContext, setContext, $state.raw, $state.eager, $derived.by, $effect.pre, ClassValue
When to use:
- Building Svelte 5 components with Runes reactivity
- Managing component state with
$stateand computed values with$derived - Creating reusable markup with snippets (replacing slots)
- Handling events with native event attributes and callback props
- Sharing state across components with context API
- Two-way binding with
$bindableprops
Key patterns covered:
- Runes:
$state,$derived,$effect,$props,$bindable,$inspect - Component composition with snippets and
{@render} - Event handling with native attributes and callback props
- Context API with
createContextfor type-safe cross-component state - Class-based reactive state with
$statefields - Deep vs shallow reactivity (
$statevs$state.raw)
When NOT to use:
- Meta-framework-specific patterns (routing, load functions, form actions) — use the corresponding meta-framework skill
- Svelte 4 patterns (
export let,$:reactive statements,<slot>,createEventDispatcher) - Server-side logic (use your meta-framework's server hooks and routes)
Detailed Resources:
- For decision frameworks and anti-patterns, see reference.md
Runes & Reactivity:
- examples/core.md -
$state,$derived,$effect,$props,$bindable, component patterns
Component Patterns:
- examples/snippets.md - Snippet blocks,
{@render}, passing snippets as props, replacing slots - examples/events.md - Event handling, component events via callback props, event modifiers
Advanced:
- examples/advanced.md -
$inspect, context API,$state.raw,$state.eager, class-based state, shared state modules
<philosophy>
Philosophy
Svelte 5 introduces Runes — a set of primitives that bring explicit, fine-grained reactivity to Svelte. Unlike Svelte 4's compiler magic ($:, export let), Runes make reactivity visible and portable across .svelte files, .ts files, and class definitions.
Core principles:
- Explicit reactivity — Runes (
$state,$derived,$effect) make reactive declarations visible. No hidden compiler transformations. - Derived over effects — Compute values with
$derived, not$effect. Effects are escape hatches, not primary tools. - Deep reactivity by default —
$statecreates deeply reactive proxies for objects/arrays. Mutations are tracked automatically. - Snippets replace slots —
{#snippet}blocks are more powerful, typed, and composable than<slot>elements. - Callback props replace event dispatchers — Pass
onsomethingcallback props instead of usingcreateEventDispatcher. - Compile-time optimization — Svelte compiles components to efficient imperative code. No virtual DOM diffing at runtime.
When to use Svelte 5 Runes:
- All new Svelte components (Runes are the default in Svelte 5)
- Reactive state in
.svelte.tsor.svelte.jsfiles - Class-based state with reactive fields
- Any computed value that depends on reactive state
When NOT to use:
- Non-reactive constants (use plain
constorlet) - Server-side code that doesn't need reactivity
- Meta-framework concerns (routing, load functions, server hooks) — use the corresponding meta-framework skill
- Svelte 4 patterns —
export let,$:, stores for component state,<slot>,createEventDispatcher
</philosophy>
<patterns>
Core Patterns
Pattern 1: Reactive State with $state
Use $state to declare reactive variables. Updates to $state variables automatically trigger UI re-renders.
<!-- counter.svelte -->
<script lang="ts">
let count = $state(0);
const STEP = 5;
function increment() {
count += 1;
}
function incrementByStep() {
count += STEP;
}
</script>
<button onclick={increment}>
Count: {count}
</button>
<button onclick={incrementByStep}>
+{STEP}
</button>
Why good: Explicit reactive declaration, named constants for magic numbers, plain function event handlers
<!-- BAD: Svelte 4 style -->
<script>
let count = 0; // Not explicitly reactive in Svelte 5 mode
$: doubled = count * 2; // Svelte 4 reactive statement
</script>
Why bad: $: is Svelte 4 syntax deprecated in Svelte 5, implicit reactivity is confusing and non-portable
Deep Reactivity
$state creates deep proxies for objects and arrays — mutations are tracked automatically:
<script lang="ts">
interface Todo {
done: boolean;
text: string;
}
let todos = $state<Todo[]>([
{ done: false, text: 'Learn Svelte 5' }
]);
function addTodo(text: string) {
todos.push({ done: false, text }); // Mutation tracked!
}
function toggleTodo(index: number) {
todos[index].done = !todos[index].done; // Deep mutation tracked!
}
</script>
Why good: No need for immutable update patterns, array methods like .push() trigger reactivity, property mutations tracked deeply
Pattern 2: Computed Values with $derived
Use $derived for values that depend on other reactive state. Never use $effect to synchronize state.
<script lang="ts">
let count = $state(0);
// Simple expression
let doubled = $derived(count * 2);
// Complex computation with $derived.by
let stats = $derived.by(() => {
const isEven = count % 2 === 0;
const isPositive = count > 0;
return { isEven, isPositive };
});
</script>
<p>{count} doubled is {doubled}</p>
<p>Even: {stats.isEven}, Positive: {stats.isPositive}</p>
Why good: Automatically recalculates when dependencies change, no side effects, push-pull reactivity avoids unnecessary recalculations
<!-- BAD: Using $effect to synchronize state -->
<script lang="ts">
let count = $state(0);
let doubled = $state(0);
$effect(() => {
doubled = count * 2; // WRONG: Use $derived instead
});
</script>
Why bad: $effect for derived state creates unnecessary reactive subscriptions, runs after DOM update (timing issues), harder to reason about data flow
Pattern 3: Component Props with $props
Use $props to declare component inputs. Supports destructuring, defaults, rest props, and TypeScript.
<!-- user-card.svelte -->
<script lang="ts">
interface Props {
name: string;
email: string;
role?: string;
class?: string;
}
let { name, email, role = 'member', ...rest }: Props = $props();
// Derived from props — updates when props change
let initials = $derived(
name.split(' ').map(n => n[0]).join('').toUpperCase()
);
</script>
<div class="user-card" {...rest}>
<span class="avatar">{initials}</span>
<h3>{name}</h3>
<p>{email}</p>
<span class="badge">{role}</span>
</div>
Why good: Type-safe props with interface, destructuring with defaults, rest props for pass-through, derived values update with prop changes
<!-- BAD: Svelte 4 style -->
<script>
export let name; // Svelte 4 prop declaration
export let email;
export let role = 'member';
</script>
Why bad: export let is Svelte 4 syntax deprecated in Svelte 5, no type safety, no rest props
Pattern 4: Two-Way Binding with $bindable
Use $bindable to declare props that support two-way binding with bind:. Use sparingly — prefer one-way data flow.
<!-- text-input.svelte -->
<script lang="ts">
interface Props {
value: string;
placeholder?: string;
}
let { value = $bindable(''), placeholder = '' }: Props = $props();
</script>
<input
bind:value={value}
{placeholder}
class="text-input"
/>
<!-- parent.svelte -->
<script lang="ts">
import TextInput from './text-input.svelte';
let searchQuery = $state('');
</script>
<TextInput bind:value={searchQuery} placeholder="Search..." />
<p>Searching for: {searchQuery}</p>
Why good: Explicit two-way binding declaration, parent controls the state, child can modify via bind:, TypeScript-safe
When to use: Form inputs, UI primitives (sliders, toggles) where two-way binding simplifies the API
When not to use: Most component communication — prefer callback props for explicit data flow
Pattern 5: Side Effects with $effect
Use $effect for side effects that need to run when reactive state changes. This is an escape hatch — prefer $derived for computed values and event handlers for user-triggered actions.
<script lang="ts">
let searchQuery = $state('');
let results = $state<string[]>([]);
const DEBOUNCE_MS = 300;
// Good: Side effect for external API calls
$effect(() => {
const query = searchQuery;
if (!query) {
results = [];
return;
}
const timer = setTimeout(async () => {
const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
results = await response.json();
}, DEBOUNCE_MS);
// Cleanup function runs before next effect and on unmount
return () => clearTimeout(timer);
});
</script>
<input bind:value={searchQuery} placeholder="Search..." />
{#each results as result}
<p>{result}</p>
{/each}
Why good: External API call is a legitimate side effect, cleanup prevents stale requests, named constant for debounce
When NOT to Use $effect
<script lang="ts">
let count = $state(0);
// BAD: Synchronizing state — use $derived
// $effect(() => { doubled = count * 2; });
// BAD: Logging in effect — use $inspect for debugging
// $effect(() => { console.log(count); });
// BAD: Calling functions on change — use event handlers
// $effect(() => { if (count > 10) showAlert(); });
// GOOD: Use $derived for computed values
let doubled = $derived(count * 2);
</script>
Pattern 6: Snippets (Replacing Slots)
Snippets are reusable markup blocks declared with {#snippet} and rendered with {@render}. They replace Svelte 4's <slot> elements.
<!-- card.svelte -->
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
title: string;
children: Snippet;
footer?: Snippet;
}
let { title, children, footer }: Props = $props();
</script>
<div class="card">
<h2>{title}</h2>
<div class="card-body">
{@render children()}
</div>
{#if footer}
<div class="card-footer">
{@render footer()}
</div>
{/if}
</div>
<!-- usage -->
<script lang="ts">
import Card from './card.svelte';
</script>
<Card title="Welcome">
<p>This becomes the children snippet automatically.</p>
{#snippet footer()}
<button>Learn More</button>
{/snippet}
</Card>
Why good: Type-safe with Snippet type, optional snippets with conditional rendering, children is implicit for content between tags
<!-- BAD: Svelte 4 slots -->
<div class="card">
<slot /> <!-- Deprecated in Svelte 5 -->
<slot name="footer" /> <!-- Use snippets instead -->
</div>
Why bad: <slot> is deprecated in Svelte 5, no type safety, less composable than snippets
Pattern 7: Event Handling
Svelte 5 uses native event attributes (onclick, onsubmit) instead of Svelte 4's on:click directive. Component events use callback props.
Element Events
<script lang="ts">
let count = $state(0);
function handleClick(event: MouseEvent) {
count += 1;
}
function handleSubmit(event: SubmitEvent) {
event.preventDefault();
// handle form
}
</script>
<button onclick={handleClick}>Clicked {count} times</button>
<!-- Inline handlers are fine for simple logic -->
<button onclick={() => count = 0}>Reset</button>
<form onsubmit={handleSubmit}>
<input name="query" />
<button type="submit">Search</button>
</form>
Component Events via Callback Props
<!-- color-picker.svelte -->
<script lang="ts">
interface Props {
color: string;
onchange?: (color: string) => void;
onreset?: () => void;
}
let { color, onchange, onreset }: Props = $props();
const COLORS = ['red', 'green', 'blue', 'purple'] as const;
</script>
{#each COLORS as c}
<button
onclick={() => onchange?.(c)}
class={{ selected: color === c }}
>
{c}
</button>
{/each}
{#if onreset}
<button onclick={onreset}>Reset</button>
{/if}
<!-- parent.svelte -->
<script lang="ts">
import ColorPicker from './color-picker.svelte';
let selectedColor = $state('red');
</script>
<ColorPicker
color={selectedColor}
onchange={(c) => selectedColor = c}
onreset={() => selectedColor = 'red'}
/>
Why good: Type-safe callback props, optional with ?. call, parent controls event handling, no indirection through dispatcher
<!-- BAD: Svelte 4 event dispatcher -->
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function handleClick() {
dispatch('change', { color: 'red' }); // Deprecated pattern
}
</script>
Why bad: createEventDispatcher is deprecated in Svelte 5, no type safety, requires manual event typing
</patterns>
<integration>
Integration Guide
Styling integration:
- Scoped
<style>blocks are the default — styles don't leak to other components - Use
:global()for global styles or CSS custom properties for parent-to-child styling - Any CSS approach (CSS Modules, utility-first, preprocessors) works with Svelte
State management:
$statefor component-local state- Context API (
createContext) for subtree-scoped state - Reactive classes with
$statefields for shared state modules (.svelte.ts) - Meta-framework load functions for server state
TypeScript integration:
- Full TypeScript support in
<script lang="ts">blocks Snippet<[ParamType]>for typed snippet props- Interface-based prop typing with
$props() ClassValuetype fromsvelte/elementsfor type-safe class props (Svelte 5.19+)
</integration>
<red_flags>
RED FLAGS
High Priority:
- Using
export letfor props — use$props()instead - Using
$:reactive statements — use$derivedor$effect - Using
<slot>or<slot name="x">— use{#snippet}and{@render} - Using
createEventDispatcher— use callback props - Using
$effectto sync state — use$derivedfor computed values - Destructuring
$stateobjects — breaks reactivity (values captured at destructure time)
Medium Priority:
- Using
on:clickdirective — useonclickattribute - Not using
$state.raw()for large API responses — unnecessary proxy overhead - Using
setContext/getContextwith string keys — usecreateContextfor type safety - Using
class:name={condition}— use built-inclassattribute object/array syntax (since 5.16)
Gotchas:
$stateproxies are not the original object — use$state.snapshot()to get a plain copy- Destructuring
$statecaptures values, not references — access properties directly instead $derivedreturn values are NOT deeply reactive — only$statecreates deep proxies$effectruns after DOM update — use$effect.pre()for pre-update timing- Dependencies after
awaitin$effectare not tracked - Context must be set during component init — cannot call
setContextin event handlers or$effect
For complete decision frameworks and the full anti-patterns list, see reference.md.
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use Svelte 5 Runes syntax — NOT Svelte 4 patterns like export let, $:, or stores for component state)
(You MUST use $derived for computed values — NEVER use $effect to synchronize state)
(You MUST use snippets ({#snippet} / {@render}) instead of slots (<slot>))
(You MUST use callback props (onclick, onsomething) instead of createEventDispatcher)
(You MUST use $state.raw() for large objects/arrays that are replaced, not mutated)
(You MUST use createContext for type-safe context instead of raw setContext/getContext with string keys)
Failure to follow these rules will produce outdated Svelte 4 code that is deprecated and will break in future versions.
</critical_reminders>