diff --git a/examples/svelte-state-rune/README.md b/examples/svelte-state-rune/README.md
new file mode 100644
index 0000000..3971f13
--- /dev/null
+++ b/examples/svelte-state-rune/README.md
@@ -0,0 +1,20 @@
+---
+name: Svelte State Rune
+description: A uses a state rune with WXT's storage to enable clean subscriptions in Svelte (and TS) as well as persisting state.
+---
+
+```sh
+npm install
+npm run dev
+```
+
+Demonstrates how the browser.storage API allows different parts of the extension share state and reflect activity on the current page.
+
+- The page fires a "counter:updated" event every second.
+- The Content Script handles these events by pushing the event payload into session storage.
+- The CounterState class watches the store and updates its reactive state property on change
+- App.svelte reflects the value of `counterState.state`
+
+Open dev tools or the extension service worker logs, click the extension's action icon and watch the events being fired by the active page update the counter.
+
+When closing and re-opening the Popup, the state is persisted.
diff --git a/examples/svelte-state-rune/index.html b/examples/svelte-state-rune/index.html
new file mode 100644
index 0000000..790b1fb
--- /dev/null
+++ b/examples/svelte-state-rune/index.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+ Document
+
+
+
Emit events
+
+
+
+
diff --git a/examples/svelte-state-rune/package.json b/examples/svelte-state-rune/package.json
new file mode 100644
index 0000000..6dce655
--- /dev/null
+++ b/examples/svelte-state-rune/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "svelte-state-rune",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "wxt",
+ "dev:firefox": "wxt -b firefox",
+ "build": "wxt build",
+ "build:firefox": "wxt build -b firefox",
+ "zip": "wxt zip",
+ "zip:firefox": "wxt zip -b firefox",
+ "check": "svelte-check --tsconfig ./tsconfig.json",
+ "postinstall": "wxt prepare"
+ },
+ "devDependencies": {
+ "@tsconfig/svelte": "^5.0.4",
+ "@wxt-dev/module-svelte": "^2.0.3",
+ "svelte": "^5.28.2",
+ "svelte-check": "^4.1.6",
+ "tslib": "^2.7.0",
+ "typescript": "^5.8.2",
+ "vite": "6.3.3",
+ "wxt": "^0.20.5"
+ }
+}
diff --git a/examples/svelte-state-rune/public/icon/128.png b/examples/svelte-state-rune/public/icon/128.png
new file mode 100644
index 0000000..9e35d13
Binary files /dev/null and b/examples/svelte-state-rune/public/icon/128.png differ
diff --git a/examples/svelte-state-rune/public/icon/16.png b/examples/svelte-state-rune/public/icon/16.png
new file mode 100644
index 0000000..cd09f8c
Binary files /dev/null and b/examples/svelte-state-rune/public/icon/16.png differ
diff --git a/examples/svelte-state-rune/public/icon/32.png b/examples/svelte-state-rune/public/icon/32.png
new file mode 100644
index 0000000..f51ce1b
Binary files /dev/null and b/examples/svelte-state-rune/public/icon/32.png differ
diff --git a/examples/svelte-state-rune/public/icon/48.png b/examples/svelte-state-rune/public/icon/48.png
new file mode 100644
index 0000000..cb7a449
Binary files /dev/null and b/examples/svelte-state-rune/public/icon/48.png differ
diff --git a/examples/svelte-state-rune/public/icon/96.png b/examples/svelte-state-rune/public/icon/96.png
new file mode 100644
index 0000000..c28ad52
Binary files /dev/null and b/examples/svelte-state-rune/public/icon/96.png differ
diff --git a/examples/svelte-state-rune/public/wxt.svg b/examples/svelte-state-rune/public/wxt.svg
new file mode 100644
index 0000000..0e76320
--- /dev/null
+++ b/examples/svelte-state-rune/public/wxt.svg
@@ -0,0 +1,15 @@
+
diff --git a/examples/svelte-state-rune/src/assets/svelte.svg b/examples/svelte-state-rune/src/assets/svelte.svg
new file mode 100644
index 0000000..8c056ce
--- /dev/null
+++ b/examples/svelte-state-rune/src/assets/svelte.svg
@@ -0,0 +1 @@
+
diff --git a/examples/svelte-state-rune/src/entrypoints/background.ts b/examples/svelte-state-rune/src/entrypoints/background.ts
new file mode 100644
index 0000000..2b548bc
--- /dev/null
+++ b/examples/svelte-state-rune/src/entrypoints/background.ts
@@ -0,0 +1,7 @@
+export default defineBackground(() => {
+ // Set the access level so `browser.storage.session` is defined and availble
+ // in content scripts: https://developer.chrome.com/docs/extensions/reference/api/storage#storage_areas
+ void browser.storage.session.setAccessLevel?.({
+ accessLevel: "TRUSTED_AND_UNTRUSTED_CONTEXTS",
+ });
+});
diff --git a/examples/svelte-state-rune/src/entrypoints/content.ts b/examples/svelte-state-rune/src/entrypoints/content.ts
new file mode 100644
index 0000000..6809f7b
--- /dev/null
+++ b/examples/svelte-state-rune/src/entrypoints/content.ts
@@ -0,0 +1,11 @@
+import { counterStore } from "@/lib/counter-store";
+
+export default defineContentScript({
+ matches: ["http://localhost/*"],
+
+ main() {
+ document.addEventListener("counter:updated", (event) => {
+ void counterStore.setValue(event.detail);
+ });
+ },
+});
diff --git a/examples/svelte-state-rune/src/entrypoints/popup/App.svelte b/examples/svelte-state-rune/src/entrypoints/popup/App.svelte
new file mode 100644
index 0000000..8fecc4c
--- /dev/null
+++ b/examples/svelte-state-rune/src/entrypoints/popup/App.svelte
@@ -0,0 +1,22 @@
+
+
+
+