The Playground
A page to write programs in the proposal's syntax, see what they compile to, and run them on Web Workers that share memory.
The playground is a page where you write programs in the proposal's syntax, see what they compile to, and run them on Web Workers that share memory. Its source is in playground/.
Using the Playground
Pick a program from the Program menu and edit it in Monaco. As you type, the page compiles the program and shows you:
- The JavaScript. Direct field access shows what the compiler emits where TypeScript proves an object is an instance of a shared struct: the field is read and written in shared memory, without the Proxy. Proxy only shows the same program with every field access going through the Proxy. The runtime's calls are marked, and the direct accesses are in bold.
- The errors. These are TypeScript's, from seeing each struct as a class, and the structs' own: a shared struct can't have methods, for example. They appear as squiggles in the editor and in a list.
- The output. Run calls the program's
main(n)on a worker, once for each count in the Workers field, which starts out as 1, 2, 4 and 8, and says how long each took and how much faster than the first: the way to see that more workers make it faster. Warm up, which is on, runsmainonce on the most workers first, unshown: each worker's JavaScript engine optimizes its hot code as it runs, and the workers are kept for the next call, so the timed runs compare workers that are all warm.mainmay block, onAtomics.Mutex.lockfor example. A program starts its own workers withrun(import.meta.url, 'name', ...args)from the agent module (src/runtime/agent.ts), which calls the function it exports asnameon a new worker. Their console output comes back to the page. Stop ends the run, along with the workers it started.
Monaco's TypeScript can't parse struct, so the editor only colors and
completes. The errors you see come from the playground's compiler.
The page remembers your edits to each program in this browser. Reset puts the original back.
Run It Locally
You need Node 22.13 or later and a recent Chrome. A static build also needs Go 1.27 or later, and git.
vp install
vp dev playground
On the dev server, programs compile in Node, on TypeScript's native API. Add
?wasm to the address to compile in the browser instead.
Static Builds
Without a dev server, the page compiles programs itself. It runs the same compiler, in a worker, on tsgo (stock TypeScript 7.1) compiled to WebAssembly, in a worker of its own. The two talk over pipes in shared memory. You get the same JavaScript and the same errors as on the dev server. The catch is size: tsgo is 46 MB, about 10 MB gzipped, and the page shows the download as it goes.
vp run build-wasm
vp build
vp run test-build
build-wasm builds tsgo from TypeScript's sources at the commit of the
TypeScript the compiler runs on, into public/compiler/. vp build builds the
page into dist/, to be served from /playground/ (set BASE for another
path). test-build serves the build with no COOP or COEP headers, so the
service worker has to isolate it. It then compiles and runs every program in
Chrome, in both modes, and checks that the JavaScript, the errors and the output
match the dev server's.
SharedArrayBuffer needs a cross-origin isolated page, which takes the COOP and COEP headers. The dev and preview servers send them. Where a host can't, as on GitHub Pages, a service worker adds them, and the page loads once more under it.
Programs
Each program exports main(n), which runs on n workers where it uses any:
- Structs: sealed, initialized in one shot, with brand-checked methods
- Shared structs across workers: a linked list that workers add to
Atomics.Mutex: workers counting togetherAtomics.Condition: a bounded queue between producers and a consumerAtomicson fields: claiming work withcompareExchange- Mandelbrot: rows claimed by workers, which scales with them, and the picture in 256 colors
- N-body: a thousand bodies split among workers, kept in step by a barrier built from a Mutex and a Condition
- N-body: direct field access against the Proxy
- The mistakes the compiler catches
Layout
| Path | What It Is |
|---|---|
index.html, main.ts |
The page, built on Monaco |
boot.ts |
The page's entry: it isolates the page, then loads main.ts |
programs/ |
The page's programs |
compile-program.ts |
A program compiled, on the dev server and in the browser alike |
vite.config.ts |
The dev server, which compiles programs, and the headers |
wasm.ts, compiler.ts |
Compiling in the browser: the page's side, and the compiler's worker |
link.ts |
A compiled program as a blob: module its workers can import too |
tsgo/ |
tsgo in WebAssembly, and the API client's channel to it |
build-wasm.ts, test-build.ts |
Building tsgo, and the static build tested in Chrome |
public/coi-sw.js |
The service worker that isolates the page where the host can't |