Skip to content

Commit c275010

Browse files
committed
feat: add GitHub Pages WASI playground
1 parent a43b4dc commit c275010

4 files changed

Lines changed: 166 additions & 0 deletions

File tree

.github/workflows/pages.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: pages
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: pages
15+
cancel-in-progress: true
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Setup Zig
25+
uses: mlugg/setup-zig@v2
26+
with:
27+
version: 0.14.1
28+
29+
- name: Build WASM runtime
30+
run: make wasi-release
31+
32+
- name: Assemble site
33+
run: |
34+
rm -rf _site
35+
mkdir -p _site
36+
cp playground/index.html _site/index.html
37+
cp playground/playground.js _site/playground.js
38+
cp gengo-test.wasm _site/gengo-test.wasm
39+
40+
- name: Upload Pages Artifact
41+
uses: actions/upload-pages-artifact@v3
42+
with:
43+
path: _site
44+
45+
deploy:
46+
environment:
47+
name: github-pages
48+
url: ${{ steps.deployment.outputs.page_url }}
49+
runs-on: ubuntu-latest
50+
needs: build
51+
steps:
52+
- name: Deploy to GitHub Pages
53+
id: deployment
54+
uses: actions/deploy-pages@v4

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,12 @@ make test
3737
- File extension is `.gengo`.
3838
- `import("std")` is the supported builtin namespace.
3939
- Language behavior may change as the project evolves.
40+
41+
## Browser Playground
42+
43+
A GitHub Pages playground is included under `playground/`.
44+
45+
- It runs the WASI `gengo-test.wasm` in-browser.
46+
- It mounts your script as an in-memory file (`script.gengo`) and executes it.
47+
48+
After pushing to `main`, the Pages workflow publishes the site.

playground/index.html

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>Gengo Playground</title>
7+
<style>
8+
:root { --bg:#0f1115; --panel:#171a21; --ink:#e6e9ef; --muted:#9aa3b2; --ok:#7ee787; --err:#ff7b72; }
9+
body { margin:0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background:var(--bg); color:var(--ink); }
10+
.wrap { max-width: 1100px; margin: 20px auto; padding: 0 16px; }
11+
h1 { font-size: 20px; margin: 0 0 12px; }
12+
.row { display:grid; grid-template-columns: 1fr 1fr; gap: 12px; }
13+
.card { background:var(--panel); border:1px solid #232938; border-radius:8px; overflow:hidden; }
14+
.card h2 { margin:0; padding:10px 12px; font-size:13px; color:var(--muted); border-bottom:1px solid #232938; }
15+
textarea, pre { width:100%; box-sizing:border-box; border:0; margin:0; padding:12px; background:transparent; color:var(--ink); font: 13px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace; }
16+
textarea { min-height: 360px; resize: vertical; outline:none; }
17+
pre { min-height: 360px; white-space: pre-wrap; }
18+
.toolbar { display:flex; gap:8px; margin: 0 0 12px; }
19+
button { background:#238636; color:#fff; border:0; padding:8px 12px; border-radius:6px; cursor:pointer; font-weight:600; }
20+
button.secondary { background:#30363d; }
21+
.status { font-size:12px; color:var(--muted); display:flex; align-items:center; }
22+
</style>
23+
</head>
24+
<body>
25+
<div class="wrap">
26+
<h1>Gengo Playground</h1>
27+
<div class="toolbar">
28+
<button id="run">Run</button>
29+
<button id="sample" class="secondary">Load Sample</button>
30+
<div id="status" class="status">Idle</div>
31+
</div>
32+
<div class="row">
33+
<div class="card">
34+
<h2>script.gengo</h2>
35+
<textarea id="src"></textarea>
36+
</div>
37+
<div class="card">
38+
<h2>Output</h2>
39+
<pre id="out"></pre>
40+
</div>
41+
</div>
42+
</div>
43+
<script type="module" src="./playground.js"></script>
44+
</body>
45+
</html>

playground/playground.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { WASI, File, OpenFile, ConsoleStdout, PreopenDirectory } from "https://cdn.jsdelivr.net/npm/@bjorn3/browser_wasi_shim@0.3.0/+esm";
2+
3+
const srcEl = document.getElementById("src");
4+
const outEl = document.getElementById("out");
5+
const runBtn = document.getElementById("run");
6+
const sampleBtn = document.getElementById("sample");
7+
const statusEl = document.getElementById("status");
8+
9+
const sample = `std := import("std")
10+
x := 2 + 3 * 4
11+
std.io.println(x)`;
12+
13+
srcEl.value = sample;
14+
15+
sampleBtn.onclick = () => {
16+
srcEl.value = sample;
17+
};
18+
19+
runBtn.onclick = async () => {
20+
runBtn.disabled = true;
21+
outEl.textContent = "";
22+
statusEl.textContent = "Running...";
23+
24+
const write = (s) => {
25+
outEl.textContent += s;
26+
};
27+
28+
try {
29+
const encoder = new TextEncoder();
30+
const script = srcEl.value;
31+
32+
const fds = [
33+
new OpenFile(new File([])), // stdin
34+
ConsoleStdout.lineBuffered((line) => write(line + "\n")), // stdout
35+
ConsoleStdout.lineBuffered((line) => write(line + "\n")), // stderr
36+
new PreopenDirectory(".", {
37+
"script.gengo": new File(encoder.encode(script)),
38+
}),
39+
];
40+
41+
const wasi = new WASI(["gengo-test.wasm", "script.gengo"], [], fds);
42+
43+
const res = await fetch("./gengo-test.wasm");
44+
if (!res.ok) throw new Error(`Failed to fetch wasm: ${res.status}`);
45+
46+
const wasm = await WebAssembly.instantiateStreaming(res, {
47+
wasi_snapshot_preview1: wasi.wasiImport,
48+
});
49+
50+
wasi.start(wasm.instance);
51+
statusEl.textContent = "Done";
52+
} catch (err) {
53+
write(String(err) + "\n");
54+
statusEl.textContent = "Error";
55+
} finally {
56+
runBtn.disabled = false;
57+
}
58+
};

0 commit comments

Comments
 (0)