Embed Raku
One script tag turns code on your page into a real, running Raku editor. It works on any host — a blog, a documentation site, a conference slide deck.
Load the script #
Anywhere in the page. Nothing to install, no build step, no npm.
<script src="https://raku.online/raku.js"></script>
Mark the code #
Any element carrying data-raku becomes editable and runnable.
<pre data-raku>say "Hello from an embedded editor!";</pre>
That markup renders this — go ahead and change it:
say "Hello from an embedded editor!";
For an empty editor to type into instead, use an empty element:
<div data-raku data-run></div>
Already have Raku code blocks? #
Add data-auto to the script tag and every existing
<pre><code class="language-raku"> block on the page becomes
runnable. You change nothing else — this is the shape Markdown, Prism,
highlight.js and the WordPress code block already emit.
<script src="https://raku.online/raku.js" data-auto></script>
If your highlighter uses a different language name, name it:
data-auto="raku perl6".
Options #
All optional. The first three go on the block, data-selector on the
script tag, and the last three work in either place — on a block for that block,
on the script tag for every block on the page.
data-run | Run once, as soon as the interpreter is ready. |
data-stdin="…" | Preset standard input, and reveal the input box. |
data-rows="N" | Initial editor height in text rows. Defaults to fitting the code. |
data-selector="…" | Use your own selector instead of [data-raku]. |
data-theme="dark" | Force light or dark. Otherwise editors follow the host page's theme, live. |
data-hide="…" | Leave parts of the editor's chrome out — the ↗ button, the exit line, the Copy buttons. The parts → |
data-playground="…" | false drops the ↗ button; a URL sends it somewhere other than raku.online, which is what a self-hosted copy needs. |
Show less #
Everything the widget draws around your code is on by default. data-hide
names the parts to leave out, separated by spaces — on one block, or on the script
tag for every block on the page.
<pre data-raku data-hide="playground exit">say "quietly";</pre>
No ↗ button, and no — exit 0 · 5 ms — under the output. Run it:
say "quietly";
run | The ▶ Run button. Pair it with data-run, or the block only shows code. |
status | The bar's status line — running…, then exit 0 · 5 ms. |
copy-code | The Copy button in the bar. |
copy-output | The Copy button on the output pane. |
playground | The ↗ button that hands the program to the full playground. |
exit | The — exit 0 · 5 ms — footer, and the same report in the bar. |
stdin | The standard-input box. A data-stdin preset is still fed to the program. |
bar | The whole top strip — run status copy-code playground at once. |
copy | Both Copy buttons. |
A block reads its own list on top of the page's, so a minus sign takes one part
back: with data-hide="playground" on the script tag, the single block
you do want to hand over carries data-hide="-playground".
The ↗ button has a second off switch, because it is the one most people try first:
data-playground="false" — or off, none, or an
empty value. Given a URL instead, that block (or the whole page, from the script tag)
opens in a playground of your own.
Match your colours #
The editor is magenta because raku.online is. Each one lives in its own Shadow DOM, so your stylesheet cannot reach inside it — with one deliberate exception: CSS custom properties do inherit across that boundary, and the widget reads its accent from one. Set it anywhere above the block.
:root { --rk-embed-accent: #0969da; } /* every editor on the page */
Or on a single wrapper, for one editor:
<div style="--rk-embed-accent: #2e7d32">
<pre data-raku>say "a green Run button";</pre>
</div>
Which renders this:
say "a green Run button";
One value covers everything the editor accents: the ▶ Run button's fill, the
■ Stop outline while a program is running, and error text in the output pane.
Nothing else about the widget is themable on purpose — the rest follows the
host page's light/dark setting, which is what
data-theme above overrides.
Host it yourself #
The script tag above loads everything from raku.online. Serving it yourself instead costs you three files and no third-party requests — it works offline, behind a firewall, and stays pinned to the version you copied.
raku.js | The widget — this page's script tag. 32 KB. |
rakujs.js | The WebAssembly loader. 110 KB. |
rakujs.wasm | The interpreter itself. 7 MB, ≈2 MB gzipped, downloaded once and cached. |
raku.js resolves the other two relative to its own URL,
so the one rule is that all three sit in the same directory. Anywhere on your
site will do. Take them straight from here:
mkdir -p your-site/raku && cd your-site/raku
curl -O https://raku.online/raku.js
curl -O https://raku.online/rakujs.js
curl -O https://raku.online/rakujs.wasm
Then point the script tag at your copy. Everything else on this page is unchanged.
<script src="/raku/raku.js"></script>
<pre data-raku>say "Hello from my own server!";</pre>
To pin the engine to a released interpreter instead, every
Raku++ release attaches
rakujs-<tag>.zip — the same rakujs.js and
rakujs.wasm, built by that release's CI:
gh release download -R ash/rakupp --pattern 'rakujs-v*.zip'
The widget raku.js is not in that zip — it belongs to this site;
take it from the URL above.
What your server must do #
- Serve
.wasmasapplication/wasm. Most static hosts already do. Without it the browser cannot stream-compile and falls back to a slower path. - Serve over
http(s). Opening the page as afile://URL will not work — the widget runs your visitors' code in a Web Worker, andfile://cannot start one. - Nothing else. Same-origin files need no CORS headers, and there is no build step, no npm package, and no server-side anything.
Two details #
- Update the three together. They are built, stamped and tested as one set; a new widget against an old
.wasmis not a combination anyone has tried. - The ↗ button on each editor hands the current program to the full playground. From your own copy it opens raku.online; send it somewhere else with
data-playground="https://example.com/play/"on the script tag, or drop it withdata-playground="false".
Three things worth knowing #
- One interpreter per page. Ten editors share a single WebAssembly instance — one download, one worker, not ten.
- It cannot break your CSS. Each editor lives in its own Shadow DOM: your styles cannot reach in, and ours cannot leak out.
- Nothing is sent anywhere. Your visitors' code runs in your visitors' browsers. There is no server, so there is nothing for you to run or pay for.
Next #
- The embed builder — set the options, see a live preview, copy the snippet.
- Every pattern, side by side — runnable blocks, stdin, empty editors, auto-enhancement, forced themes.