diff --git a/tools/playground.html b/tools/playground.html
new file mode 100644
index 0000000..da39e79
--- /dev/null
+++ b/tools/playground.html
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Ctrl+Enter to run
+
+
+
+
+
diff --git a/tools/playground.nim b/tools/playground.nim
new file mode 100644
index 0000000..94f5593
--- /dev/null
+++ b/tools/playground.nim
@@ -0,0 +1,105 @@
+# playground.nim — Bux language web playground
+# Uses hunos HTTP server to accept Bux code, compile with buxc, run, and return output
+#
+# Usage: nim c -r tools/playground.nim
+# Then open http://localhost:8407 in browser
+
+import std/[os, osproc, strutils, json]
+import hunos, hunos/router
+
+const
+ Buxc = "./buxc" # path to buxc binary
+ Port = 8407 # playground port
+ TimeoutMs = 5000 # max execution time (5 seconds)
+
+# --------------- HTML frontend ---------------
+const PlaygroundHTML = staticRead("playground.html")
+
+# --------------- helpers ---------------
+
+proc compileAndRun(code: string): tuple[output: string, exitCode: int, isError: bool] =
+ ## Compile code with buxc, run the resulting binary, capture output.
+ var tmpDir = "/tmp/bux-playground-" & $getCurrentProcessId()
+ createDir(tmpDir)
+ createDir(tmpDir / "src")
+
+ # Write Main.bux
+ writeFile(tmpDir / "src" / "Main.bux", code)
+
+ # Write bux.toml
+ writeFile(tmpDir / "bux.toml", "[package]\nname = \"playground\"\nversion = \"0.1.0\"\ntype = \"bin\"\n\n[build]\noutput = \"Bin\"\n")
+
+ # Build with buxc
+ let buildResult = execCmdEx(Buxc & " build " & tmpDir)
+ let buildOutput = buildResult.output
+
+ if buildResult.exitCode != 0:
+ removeDir(tmpDir)
+ return (buildOutput, buildResult.exitCode, true)
+
+ # Run the binary (named "playground" from bux.toml)
+ let binary = tmpDir / "build" / "playground"
+ if not fileExists(binary):
+ removeDir(tmpDir)
+ return ("Binary not found after build:\n" & buildOutput, 1, true)
+
+ let runResult = execCmdEx("timeout " & $TimeoutMs div 1000 & " " & binary)
+ let runOutput = runResult.output
+
+ # Cleanup
+ removeDir(tmpDir)
+
+ return (buildOutput & "\n" & runOutput, runResult.exitCode, runResult.exitCode != 0)
+
+# --------------- route handlers ---------------
+
+proc handlePlayground(request: Request) =
+ var headers: HttpHeaders
+ headers["Content-Type"] = "text/html; charset=utf-8"
+ request.respond(200, headers, PlaygroundHTML)
+
+proc handleCompile(request: Request) =
+ if request.httpMethod != HttpPost:
+ var headers: HttpHeaders
+ headers["Content-Type"] = "text/plain"
+ request.respond(405, headers, "Method not allowed")
+ return
+
+ let code = request.body
+
+ if code.len == 0:
+ var headers: HttpHeaders
+ headers["Content-Type"] = "application/json"
+ request.respond(400, headers, $(%*{"error": "no code provided"}))
+ return
+
+ let (output, exitCode, isError) = compileAndRun(code)
+
+ var headers: HttpHeaders
+ headers["Content-Type"] = "application/json"
+ headers["Access-Control-Allow-Origin"] = "*"
+
+ let response = $(%*{
+ "output": output,
+ "exitCode": exitCode,
+ "isError": isError
+ })
+
+ request.respond(200, headers, response)
+
+# --------------- main ---------------
+
+proc main() =
+ echo "Bux Playground"
+ echo "Serving on http://localhost:" & $Port
+ echo "Open your browser and start coding!"
+
+ var router: Router
+ router.get("/", handlePlayground)
+ router.post("/compile", handleCompile)
+
+ let server = newServer(router)
+ server.serve(Port(Port))
+
+when isMainModule:
+ main()