Spaces:
Running
Running
add simulated NetBSD xearth demo
Browse files- README.md +10 -5
- index.html +67 -48
README.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: opencode_web
|
| 3 |
+
emoji: 🌍
|
| 4 |
+
colorFrom: green
|
| 5 |
+
colorTo: gray
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
---
|
| 9 |
|
| 10 |
+
# opencode_web
|
| 11 |
+
|
| 12 |
+
Minimal pure HTML+JS demo: a simulated NetBSD boot log plus an xearth-style
|
| 13 |
+
rotating globe (tinyx-wscons + xearth concept).
|
| 14 |
+
|
| 15 |
+
This is a simulation, not a real NetBSD VM.
|
index.html
CHANGED
|
@@ -1,51 +1,70 @@
|
|
| 1 |
<!doctype html>
|
| 2 |
-
<html
|
| 3 |
-
<
|
| 4 |
-
<
|
| 5 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
<script>
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
</script>
|
| 16 |
-
<
|
| 17 |
-
<
|
| 18 |
-
const CX_URL = "https://cxrtnc.leaningtech.com/1.4.0/cx.esm.js";
|
| 19 |
-
const term = new Terminal({ cursorBlink: true, convertEol: true, fontFamily: "monospace" });
|
| 20 |
-
term.open(document.getElementById("console"));
|
| 21 |
-
term.focus();
|
| 22 |
-
term.write("opencode web: loading CheerpX + Alpine...\r\n");
|
| 23 |
-
try {
|
| 24 |
-
if (!crossOriginIsolated) throw new Error("page is not cross-origin isolated yet (service worker reload pending)");
|
| 25 |
-
const CheerpX = await import(CX_URL);
|
| 26 |
-
const blockDevice = await CheerpX.HttpBytesDevice.create("rootfs.ext2");
|
| 27 |
-
const cache = await CheerpX.IDBDevice.create("opencode-web-v1");
|
| 28 |
-
const overlay = await CheerpX.OverlayDevice.create(blockDevice, cache);
|
| 29 |
-
const webDevice = await CheerpX.WebDevice.create("");
|
| 30 |
-
const dataDevice = await CheerpX.DataDevice.create();
|
| 31 |
-
const cx = await CheerpX.Linux.create({ mounts: [
|
| 32 |
-
{ type: "ext2", dev: overlay, path: "/" },
|
| 33 |
-
{ type: "dir", dev: webDevice, path: "/web" },
|
| 34 |
-
{ type: "dir", dev: dataDevice, path: "/data" },
|
| 35 |
-
{ type: "devs", path: "/dev" },
|
| 36 |
-
{ type: "devpts", path: "/dev/pts" },
|
| 37 |
-
{ type: "proc", path: "/proc" },
|
| 38 |
-
{ type: "sys", path: "/sys" },
|
| 39 |
-
] });
|
| 40 |
-
const readFn = cx.setCustomConsole((buf, vt) => { if (vt === 1) term.write(new Uint8Array(buf)); }, term.cols, term.rows);
|
| 41 |
-
term.onData(s => { for (let i = 0; i < s.length; i++) readFn(s.charCodeAt(i)); });
|
| 42 |
-
await cx.run("/bin/sh", ["-c", "opencode; exec /bin/sh -l"], {
|
| 43 |
-
env: ["HOME=/root", "TERM=xterm-256color", "PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin", "LANG=C.UTF-8"],
|
| 44 |
-
cwd: "/root", uid: 0, gid: 0,
|
| 45 |
-
});
|
| 46 |
-
} catch (e) {
|
| 47 |
-
term.write("\r\nERROR: " + e + "\r\n");
|
| 48 |
-
console.error(e);
|
| 49 |
-
}
|
| 50 |
-
</script>
|
| 51 |
-
</body></html>
|
|
|
|
| 1 |
<!doctype html>
|
| 2 |
+
<html lang="zh-Hant">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
| 6 |
+
<title>opencode_web - NetBSD demo (simulated)</title>
|
| 7 |
+
<style>
|
| 8 |
+
html,body{margin:0;height:100%;background:#000;color:#ccc;font:14px/1.4 monospace}
|
| 9 |
+
#term{white-space:pre;padding:12px;height:40%;overflow:hidden;box-sizing:border-box}
|
| 10 |
+
#wrap{display:flex;justify-content:center;align-items:center;height:60%}
|
| 11 |
+
canvas{background:#000;border:1px solid #333}
|
| 12 |
+
.tag{color:#666;padding:0 12px 6px}
|
| 13 |
+
</style>
|
| 14 |
+
</head>
|
| 15 |
+
<body>
|
| 16 |
+
<div id="term"></div>
|
| 17 |
+
<div id="wrap"><canvas id="c" width="480" height="360"></canvas></div>
|
| 18 |
+
<div class="tag">simulated: pure HTML+JS, NOT a real NetBSD VM. xearth-style globe (tinyx-wscons demo)</div>
|
| 19 |
<script>
|
| 20 |
+
(function () {
|
| 21 |
+
// ---- fake NetBSD boot log (typed out) ----
|
| 22 |
+
const lines = [
|
| 23 |
+
"NetBSD 10.0 (GENERIC) #0: (simulated)",
|
| 24 |
+
"total memory = 64 MB",
|
| 25 |
+
"cpu0 at mainbus0: i386-like (simulated)",
|
| 26 |
+
"wscons0: attached tinyx-wscons",
|
| 27 |
+
"xearth: starting globe renderer",
|
| 28 |
+
"login: demo (type nothing, enjoy the globe)",
|
| 29 |
+
""
|
| 30 |
+
];
|
| 31 |
+
const term = document.getElementById("term");
|
| 32 |
+
let li = 0, ci = 0, buf = "";
|
| 33 |
+
function type() {
|
| 34 |
+
if (li >= lines.length) return;
|
| 35 |
+
const line = lines[li];
|
| 36 |
+
buf += line[ci++] || "";
|
| 37 |
+
if (ci > line.length) { buf += "\n"; li++; ci = 0; }
|
| 38 |
+
term.textContent = buf + (li < lines.length ? "_" : "");
|
| 39 |
+
setTimeout(type, li < lines.length && ci === 0 ? 300 : 25);
|
| 40 |
+
}
|
| 41 |
+
type();
|
| 42 |
+
|
| 43 |
+
// ---- xearth-style rotating dotted globe ----
|
| 44 |
+
const cv = document.getElementById("c"), g = cv.getContext("2d");
|
| 45 |
+
const W = cv.width, H = cv.height, R = 150, cx = W / 2, cy = H / 2;
|
| 46 |
+
const pts = [];
|
| 47 |
+
for (let i = 0; i < 1400; i++) { // Fibonacci sphere points
|
| 48 |
+
const y = 1 - (2 * i) / 1399, r = Math.sqrt(1 - y * y), t = i * Math.PI * (3 - Math.sqrt(5));
|
| 49 |
+
pts.push([Math.cos(t) * r, y, Math.sin(t) * r]);
|
| 50 |
+
}
|
| 51 |
+
let rot = 0;
|
| 52 |
+
function frame() {
|
| 53 |
+
g.fillStyle = "#000"; g.fillRect(0, 0, W, H);
|
| 54 |
+
const c = Math.cos(rot), s = Math.sin(rot);
|
| 55 |
+
for (const [x, y, z] of pts) {
|
| 56 |
+
const X = x * c + z * s, Z = -x * s + z * c; // rotate around Y axis
|
| 57 |
+
if (Z < 0) continue; // front side only
|
| 58 |
+
const px = cx + X * R, py = cy - y * R;
|
| 59 |
+
const shade = 0.35 + 0.65 * Z;
|
| 60 |
+
g.fillStyle = `rgba(80,${Math.round(200 * shade)},120,${shade})`;
|
| 61 |
+
g.fillRect(px, py, 2, 2);
|
| 62 |
+
}
|
| 63 |
+
rot += 0.01;
|
| 64 |
+
requestAnimationFrame(frame);
|
| 65 |
+
}
|
| 66 |
+
frame();
|
| 67 |
+
})();
|
| 68 |
</script>
|
| 69 |
+
</body>
|
| 70 |
+
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|