Spaces:
Running
Running
restore original CheerpX VM index.html and README (revert accidental overwrite)
Browse files- README.md +5 -10
- index.html +48 -67
README.md
CHANGED
|
@@ -1,15 +1,10 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
| 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.
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Opencode Web
|
| 3 |
+
emoji: 🏢
|
| 4 |
+
colorFrom: pink
|
| 5 |
+
colorTo: indigo
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
---
|
| 9 |
|
| 10 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
index.html
CHANGED
|
@@ -1,70 +1,51 @@
|
|
| 1 |
<!doctype html>
|
| 2 |
-
<html
|
| 3 |
-
<
|
| 4 |
-
<
|
| 5 |
-
<
|
| 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 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
"
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 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 |
-
</
|
| 70 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
<!doctype html>
|
| 2 |
+
<html><head><meta charset="utf-8"><title>opencode web</title>
|
| 3 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/css/xterm.css">
|
| 4 |
+
<style>html,body{margin:0;height:100%;background:#000}#console{height:100%}</style>
|
| 5 |
+
</head><body><div id="console"></div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
<script>
|
| 7 |
+
// Cross-origin isolation (needed by CheerpX) via service worker, since static hosting cannot set headers.
|
| 8 |
+
if ("serviceWorker" in navigator && !crossOriginIsolated) {
|
| 9 |
+
navigator.serviceWorker.register("sw.js").then(reg => {
|
| 10 |
+
if (reg.active && navigator.serviceWorker.controller) return;
|
| 11 |
+
navigator.serviceWorker.addEventListener("controllerchange", () => location.reload());
|
| 12 |
+
if (reg.active) location.reload();
|
| 13 |
+
});
|
| 14 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
</script>
|
| 16 |
+
<script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/lib/xterm.js"></script>
|
| 17 |
+
<script type="module">
|
| 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>
|