From 2cdc7c520f5c994f3d18a48c1bd71e70bbc6e063 Mon Sep 17 00:00:00 2001 From: arko33 <221298156+arko33@users.noreply.github.com> Date: Thu, 22 Oct 2026 02:26:48 +0700 Subject: [PATCH] =?UTF-8?q?feat:=20/city=20rebuilt=20as=20a=203D=20playgro?= =?UTF-8?q?und=20mirror=20=E2=80=94=20same=20layout,=20real=20stream?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ghost/ghost.mjs | 230 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 229 insertions(+), 1 deletion(-) diff --git a/packages/ghost/ghost.mjs b/packages/ghost/ghost.mjs index 9987e61..41d8466 100644 --- a/packages/ghost/ghost.mjs +++ b/packages/ghost/ghost.mjs @@ -195,6 +195,229 @@ tick();setInterval(tick,1600);addEventListener("resize",draw); `; } +// Ghost City 3D — same layout language as the published playground (3D city in +// the center, info panel left, selected-tower panel right, turn dock bottom), +// but stream-fed from the recorder's own /session, so ANY project gets the +// full experience from `ghost watch` alone. three.js is loaded from a CDN in +// the browser (the recorder itself stays zero-dependency); if the browser is +// offline the 2D canvas city at /city2d is still served by the recorder. +function cityHtml3d() { + return ` + +Ghost City — live playground (3D) + + + +

Ghost City

connecting… + studio · session · 2D fallback +
+
+ +
+ +
+
turns
+`; +} + // ── helpers ────────────────────────────────────────────────────────────────── // Parse a unified diff into per-file churn (added+deleted lines) used as the // 3D city "height" — so towers stay a fact of the recording, never invented. @@ -319,6 +542,11 @@ async function cmdWatch() { return; } if (req.method === "GET" && req.url === "/city") { + res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" }); + res.end(cityHtml3d()); + return; + } + if (req.method === "GET" && req.url === "/city2d") { res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" }); res.end(cityHtml()); return; @@ -429,7 +657,7 @@ async function cmdWatch() { if (!session.head) console.log(` git none — file recording only (run git init to enable shadow-git checkpoints)`); console.log(` app ${appUrl}`); console.log(` studio ${eventsBase} ← detail: turns, checkpoints, samples`); - console.log(` city ${eventsBase}/city ← playground kota live (tanpa npm run dev)`); + console.log(` city ${eventsBase}/city ← playground kota 3D live (tanpa npm run dev)`); console.log(` replay full 3D dashboard: repo → npm run dev → /playground?live=1`); console.log(` adapter ${eventsBase}/events (OpenCode plugin target)`); console.log(` sync ${sync}${sync === "off" ? " (local-only) — run: ghost setup to enable" : ""}`);