svelte/playground
Svelte Playground for Runes, Transitions and Components
Answer a small Svelte question in the time it takes to ask it — a rune recomputing, a transition playing, a style refusing to leak — with the console sitting beside the running component.
<script>
let n = $state(0)
let big = $derived(n > 5)
$effect(() => console.log('n is', n))
</script>
<button onclick={() => n++}>{n}</button>
{#if big}<p>past five</p>{/if}
01 platform
Why runes are best understood by running them
The gap between Svelte 4's implicit reactivity and Svelte 5's explicit runes is where nearly all the confusion lives, and it closes faster by watching than by reading.
-
$derivedrecomputes, it is never assignedThat single sentence is the whole migration, and it stops being abstract the second you try to assign to one and read the compiler's objection.
-
Deep proxying is visible
$stateproxies nested objects so mutation is tracked. Mutate a field two levels down, watch it update, then try the same with$state.rawand watch it not. -
$effectshows its own dependenciesLog inside one and the console names which change re-ran it — including the dependency you did not realise you had read.
-
Transitions are one import away
svelte/transitionneeds nothing installed, so tryingflyagainstfadeagainst aspringis three edits rather than three package decisions.
02 pipeline
Testing a rune, start to finish
Four moves. This is what checking a reactivity question costs here, against the minutes a local scaffold costs before the first line of your own code.
-
Declare the state
let x = $state(...)in a component, or in a.svelte.tsmodule if the question is about sharing it. Two files the moment the question involves more than one component. -
Derive from it
Add a
$derivedthat reads it and a$effectthat logs. Those two lines are the instrumentation for almost every reactivity question worth asking. -
Provoke it
Mutate deeply, reassign wholesale, swap
$statefor$state.raw. Each variant prints its own trace beside the running component, so cause and effect stay adjacent. -
Share the trace
Send the link. Whoever opens it gets the same runes, the same logs and the same reproduction — which is what an issue thread actually needs.
03 features
What the playground gives a Svelte experiment
Everything below matters for testing Svelte behavior specifically, rather than for building an application.
-
Svelte 5 compiled on save
Single-digit milliseconds for a component. The compiler runs on your device, so there is no container to boot and no queue to wait in.
-
Runes in modules too
.svelte.tsfiles compile here, so a question about sharing state between components is testable rather than theoretical. -
Transitions with no install
svelte/transitionandsvelte/motionship with the framework, so comparingflytospringis an edit rather than a dependency decision. -
Scoped styles, provably
Write two components that both style
.cardand watch neither leak. The compiler's scoping attribute is visible in the rendered output. -
Console beside the component
console.logfrom an$effectlands where you can read it, in the order the compiler actually ran things. -
A link that reproduces
Share the project and it opens as you left it, which is what makes it usable on a GitHub issue rather than as a screenshot.
04 deep dive
Watching a derived value recompute
Most Svelte 5 questions reduce to one thing: what re-ran, and why. An instant compile loop answers that by demonstration.
Put a log inside $derived and read it twice. It runs once. The caching stops being a claim in the docs and becomes something you watched happen.
Mutate deep, then reassign. $state proxies nested objects, so obj.a.b = 1 is tracked. Swap to $state.raw and the same mutation goes unnoticed until you replace the whole object.
$effect runs after the DOM updates. That ordering matters when an effect reads a node, and the only reliable way to build the intuition is to log on both sides of it.
Untracked reads exist for a reason. Reading a value without creating a dependency is occasionally what you want, and seeing an effect stop re-running is how that becomes obvious.
- derived
- cached, recomputed
- state
- deep proxy
- raw
- reassignment only
- effect
- after DOM update
<script>
let items = $state([{ n: 1 }])
let total = $derived.by(() => {
console.log('recomputed')
return items.reduce((s, i) => s + i.n, 0)
})
</script>
05 workflow
A reactivity surprise, and the fix
One real sequence, from opening the tab to understanding why something did not update. The console sits beside the component, so nothing here needed devtools.
- open → Svelte playground
- compile 5ms · mounted
- [log] recomputed · total 1
- edit → $state.raw(items)
- click → mutate items[0].n
- no recompute — raw tracks reassignment only
- items = [...items] → save
- recomputed · total 2
-
The compiler is fast enough to iterate
A five-millisecond compile means trying four variants costs less than reading one paragraph about which to pick.
-
Nothing hides in a build step
There is no bundler between the file and the output, so what you see running is what the compiler produced from what you wrote.
-
Recovery is one save
Change the line and save. The component swaps in place; there is no dev server to restart.
06 deep dive
When state changes and nothing moves
Almost every Svelte 5 bug report is this shape, and almost all of them have one of three causes.
Something was destructured out of reactivity. Pulling a value out of a $state object gives you the value, not the binding. The fix is to read it where you use it.
$state.raw was the wrong choice. Raw state only notices reassignment, which is exactly right for a large array you always replace and exactly wrong for one you mutate.
A $derived was assigned to. Derived values are computed rather than set. The compiler says so, and reproducing the error once is faster than remembering the rule.
- destructuring
- breaks the binding
- raw
- reassignment only
- derived
- never assigned
- restart
- never needed
<script>
let user = $state({ name: 'Ada' })
// reads once — not reactive
const { name } = user
// reactive — read at use site
// {user.name}
</script>
07 ecosystem
A project that mixes compilers
A .svelte file can sit beside a .vue one and a Python script; XCODX picks the compiler per file rather than per project.
08 languages
Every language the editor knows
Highlighting and IntelliSense cover 70+ languages. These are the ones XCODX also compiles or executes for you.
Compiled in your browser11
Zero build step. Transform runs on a Web Worker, so typing never blocks.
- JSX
- TSX
- TypeScript
- Vue SFC
- Svelte
- Angular (JIT)
- SolidJS
- SCSS
- Sass
- Less
- Pug
Rendered natively8
Straight to the live preview, no transform in the way.
- HTML
- CSS
- JavaScript
- JSON
- Markdown
- Jupyter (.ipynb)
- SVG
- YAML
Executed on demand22
70+ languages run through a self-hosted Piston engine. stdout, stderr, images and tracebacks land in the console.
- Python
- Java
- C
- C++
- C#
- Go
- Rust
- Ruby
- PHP
- Kotlin
- Swift
- Lua
- Scala
- Perl
- Haskell
- Elixir
- Dart
- R
- Julia
- SQLite
- Bash
- PowerShell
09 questions
Using the Svelte playground — common questions
Questions about the fast loop specifically.
How does this compare to the REPL on svelte.dev?
The official REPL is built to teach the language and is very good at it. This keeps the same instant compile but adds a file tree, npm packages and Git, so an experiment that grows past one component does not have to move somewhere else.
Why did my state change without the UI updating?
Usually destructuring. Pulling a value out of a $state object copies it rather than keeping the binding, so the copy never changes. Read the property where you use it instead, and the reactivity comes back.
When should I use $state.raw instead of $state?
When the value is large and you always replace it wholesale rather than mutating into it — a big table of rows, say. Deep proxying costs something on those, and raw state skips it by tracking reassignment only.
Can I test state shared between components?
Yes, and it is one of the better reasons to use a multi-file playground. Declare $state in a .svelte.ts module, export it, import it in two components, and watch both update without a store or a subscription.
Do transitions and springs work?
Yes, with nothing installed. svelte/transition and svelte/motion ship with the framework, so comparing fly against fade against a spring is three edits in the same tab.
Can I check that scoped styles really scope?
Yes, and it is worth doing once. Write two components that both style .card, look at the rendered output, and the compiler's per-component attribute is right there in the markup.
Does Svelte 4 syntax still compile?
Yes. Svelte 5 kept the older reactive syntax working, so a component using export let and $: labels compiles alongside one using runes. That is what makes an incremental migration testable here.
Does the playground work offline?
Once loaded, yes. XCODX installs as a Progressive Web App and the Svelte compiler runs on your device, so editing and compiling keep working with no connection. Only installing a new package needs the network.
Do I need to install anything to use XCODX Studio?
No. XCODX Studio is a browser-based IDE — the editor, the compilers and the preview all run client-side. There is no download, no package manager to set up and no configuration file to write. Opening the editor is the whole setup step.
Where is my code stored?
In your own browser. Projects, file history and Git objects live in local storage on your device and are never uploaded to a server. That also means XCODX works offline: it is a Progressive Web App, so you can install it and keep coding with no connection.
Is XCODX Studio free?
Yes. The editor, the live preview, the 70+ language runtimes, npm installs, Git and the integrated terminal are all free to use.
Can I use XCODX on a tablet or Chromebook?
Yes. The editor is a responsive web app, so a Chromebook, an iPad or an Android tablet gets the same compilers and the same preview a laptop does — there is no desktop-only build, because there is no build to install at all. The layout adapts to the screen rather than shrinking a desktop UI into it.
Can I export a project or move it to my own machine?
Yes. Export the whole project as a zip with its folder structure intact and open it locally, or commit it and push. It is ordinary source on disk from that point on — no proprietary format and no lock-in, which is also why importing an existing repository from GitHub works the same way in reverse.
Nothing to install
Open the Svelte playground
A component compiled and a rune recomputing in seconds, with the console beside it and a link to hand over when it does something interesting.
