From 12927ca6f3a1b1862d685b43975891b6c04cb9e9 Mon Sep 17 00:00:00 2001 From: Eva Date: Thu, 30 Jul 2026 12:49:54 +0700 Subject: [PATCH] tools: preserve GEX44 box tooling before decommission (ComfyUI detail-finisher lane, unity save/launch ops, gbuffer derivation, display config) --- tools/gex44-box/README.md | 41 + .../comfyui-detail-finisher/README-WORLDOS.md | 65 ++ .../comfyui-detail-finisher/tile_detail.sh | 111 +++ .../workflows/tile_detail.json | 76 ++ .../display-config/1440-fallback.Xresources | 6 + .../display-config/4k-readable.Xresources | 6 + .../display-config/4k-workspace.Xresources | 6 + .../display-config/gex44-display-profile | 50 ++ .../gtk-settings.ini.4k-readable | 8 + .../display-config/openbox-rc.xml.4k-readable | 753 ++++++++++++++++++ .../sunshine-apps.4k-readable.json | 50 ++ .../unity-desktop.sh.4k-readable | 21 + .../xorg-service-4k-readable.conf | 3 + .../display-config/xorg.conf.4k-readable | 40 + tools/gex44-box/ops/INSTALL.md | 139 ++++ tools/gex44-box/ops/derive_gbuffer.py | 23 + tools/gex44-box/ops/launch_editor.sh | 5 + tools/gex44-box/ops/setup_depth.sh | 6 + tools/gex44-box/ops/worldos-unity-save.sh | 24 + 19 files changed, 1433 insertions(+) create mode 100644 tools/gex44-box/README.md create mode 100644 tools/gex44-box/comfyui-detail-finisher/README-WORLDOS.md create mode 100755 tools/gex44-box/comfyui-detail-finisher/tile_detail.sh create mode 100644 tools/gex44-box/comfyui-detail-finisher/workflows/tile_detail.json create mode 100644 tools/gex44-box/display-config/1440-fallback.Xresources create mode 100644 tools/gex44-box/display-config/4k-readable.Xresources create mode 100644 tools/gex44-box/display-config/4k-workspace.Xresources create mode 100755 tools/gex44-box/display-config/gex44-display-profile create mode 100644 tools/gex44-box/display-config/gtk-settings.ini.4k-readable create mode 100644 tools/gex44-box/display-config/openbox-rc.xml.4k-readable create mode 100644 tools/gex44-box/display-config/sunshine-apps.4k-readable.json create mode 100755 tools/gex44-box/display-config/unity-desktop.sh.4k-readable create mode 100644 tools/gex44-box/display-config/xorg-service-4k-readable.conf create mode 100644 tools/gex44-box/display-config/xorg.conf.4k-readable create mode 100644 tools/gex44-box/ops/INSTALL.md create mode 100644 tools/gex44-box/ops/derive_gbuffer.py create mode 100755 tools/gex44-box/ops/launch_editor.sh create mode 100644 tools/gex44-box/ops/setup_depth.sh create mode 100755 tools/gex44-box/ops/worldos-unity-save.sh diff --git a/tools/gex44-box/README.md b/tools/gex44-box/README.md new file mode 100644 index 00000000..bd19ef41 --- /dev/null +++ b/tools/gex44-box/README.md @@ -0,0 +1,41 @@ +# GEX44 box — preserved tooling & reproducible setup + +The GEX44 GPU box (`root@46.4.26.123`, RTX 4000 Ada / 64GB) was WorldOS's primary Unity render +host + image-detail lane. It is being decommissioned. This directory versions the box-only tooling +that previously lived nowhere but the box, so the setup is reproducible and nothing is lost with the +hardware. + +**The canonical Unity project itself is NOT here** — it is fully committed and pushed to +`github.com/100yenadmin/worldos-unity-2026-06-30_07-21-47` (incl. Git-LFS). This dir is the +*surrounding* ops/tooling that sat outside that repo. + +## Contents + +### `ops/` +- **`worldos-unity-save.sh`** — the box's autosave mechanism (cron, runs as `unity`): commit-if-dirty + locally + best-effort LFS push. `--push` does the daily GitHub push. This is the persistence + contract referenced across the WorldOS runbooks ("end every box session with this"). +- **`launch_editor.sh`** — headless/hidpi Unity editor launcher for the box. +- **`derive_gbuffer.py`** — depth/normal G-buffer derivation for the render pipeline. +- **`setup_depth.sh`** — depth-pass environment setup. +- **`INSTALL.md`** — box bring-up / install notes. + +### `comfyui-detail-finisher/` +A headless ComfyUI lane for a **tiled, structure-locked SDXL img2img detail pass** on painterly game +backdrops (denoise ~0.35, SDXL base + Tile ControlNet, tiled via Ultimate SD Upscale so large plates +fit in VRAM; keeps input resolution/aspect). Ran on `127.0.0.1:8188`. +- `README-WORLDOS.md` — full start/stop + usage. +- `tile_detail.sh` — driver script. +- `workflows/tile_detail.json` — the ComfyUI workflow graph (the reusable asset). + +### `display-config/` +The 4K-readable remote-desktop (Xorg/openbox/sunshine) profile used to drive the headed editor over +a remote session. + +## Not committed here (archived on LEXAR only) +- The vLLM model-serving scripts (`h4-vllm-*.sh`) — a separate, non-WorldOS use of the GPU box. +- ComfyUI `output/` sample renders + `user/comfyui.db`. +- Full box render caches (`Captures*`, `BuildOutput`) — regenerable; the curated renders live in + the WorldOS session-notes. + +Backup location: `LEXAR/Codex/session-notes/2026-07-24/worldos-disk-cleanup-fork/artifacts/`. diff --git a/tools/gex44-box/comfyui-detail-finisher/README-WORLDOS.md b/tools/gex44-box/comfyui-detail-finisher/README-WORLDOS.md new file mode 100644 index 00000000..6cf8dc99 --- /dev/null +++ b/tools/gex44-box/comfyui-detail-finisher/README-WORLDOS.md @@ -0,0 +1,65 @@ +# ComfyUI "detail-finisher" lane (WorldOS) + +A headless ComfyUI install for a **tiled, structure-locked SDXL img2img detail pass** on +painterly game backdrops. Takes an input PNG (~1344x768 to 2760x1504) and runs a +denoise-~0.35 "detail" pass using SDXL base + an SDXL **Tile ControlNet** (structure lock), +tiled via **Ultimate SD Upscale (No Upscale)** so large backdrops fit in VRAM. Output keeps +the input resolution and aspect ratio. + +Runs on `127.0.0.1:8188`. **Do NOT touch ports 8080 / 8765 or the `unity` user's editor +(pid on 8080).** This lane only owns the ComfyUI process and files under `/root/comfyui`. + +## Start it + +```bash +cd /root/comfyui && nohup venv/bin/python main.py --listen 127.0.0.1 --port 8188 > comfy.log 2>&1 & disown +# wait ~10s, then: +curl -s http://127.0.0.1:8188/system_stats +``` + +## Stop it (only ever this specific process — NEVER a broad pkill) + +```bash +PID=$(pgrep -f "main.py --listen 127.0.0.1 --port 8188" | head -1) +kill "$PID" +``` + +## Driver script + +```bash +/root/comfyui/tile_detail.sh +# example (the proven proof pass): +/root/comfyui/tile_detail.sh /tmp/crisp_diff.png /tmp/crisp_diff_tiled.png 0.35 +``` + +The driver uploads the input via the `/upload/image` API, loads +`/root/comfyui/workflows/tile_detail.json`, patches in the input filename + denoise, +POSTs to `/prompt`, polls `/history/` until done, and copies the SaveImage output +(from `/root/comfyui/output/`) to ``. + +Proven proof pass: input 2760x1504 -> output 2760x1504, ~164s, peak ~12.4 GB VRAM, +output mean pixel 0.348 (valid, non-black). + +## Pipeline (workflows/tile_detail.json, API format) + +`CheckpointLoaderSimple` -> `LoadImage` -> `CLIPTextEncode` (pos/neg) -> +`ControlNetLoader` (tile) -> `ControlNetApplyAdvanced` (strength 0.75, applied to the +source image = structure lock) -> `UltimateSDUpscaleNoUpscale` +(denoise 0.35, cfg 6.0, dpmpp_2m/karras, 24 steps, 1024x1024 tiles, tiled_decode, +Band-Pass seam fix) -> `SaveImage`. + +To change detail strength, pass a different denoise arg (0.25 subtle .. 0.45 aggressive); +higher drifts further from the source structure. + +## Models + +| File | Path | Size (bytes) | Size (h) | Source | +|------|------|-------------|----------|--------| +| sd_xl_base_1.0.safetensors | /root/comfyui/models/checkpoints/ | 6938078334 | 6.5G | huggingface.co/stabilityai/stable-diffusion-xl-base-1.0 (sd_xl_base_1.0.safetensors) | +| controlnet-tile-sdxl.safetensors | /root/comfyui/models/controlnet/ | 2502139104 | 2.4G | huggingface.co/xinsir/controlnet-tile-sdxl-1.0 (diffusion_pytorch_model.safetensors, renamed) | + +## Env + +- venv: `/root/comfyui/venv` (torch 2.6.0+cu124, CUDA available on RTX 4000 SFF Ada) +- custom node: `ComfyUI_UltimateSDUpscale` (ssitu) in `/root/comfyui/custom_nodes/` +- log: `/root/comfyui/comfy.log` diff --git a/tools/gex44-box/comfyui-detail-finisher/tile_detail.sh b/tools/gex44-box/comfyui-detail-finisher/tile_detail.sh new file mode 100755 index 00000000..b5b353d7 --- /dev/null +++ b/tools/gex44-box/comfyui-detail-finisher/tile_detail.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +# tile_detail.sh +# Runs a tiled, structure-locked SDXL + Tile-ControlNet img2img detail pass +# through the local ComfyUI HTTP API (127.0.0.1:8188) and writes the result to . +set -euo pipefail + +IN="${1:?usage: tile_detail.sh }" +OUT="${2:?usage: tile_detail.sh }" +DENOISE="${3:-0.35}" + +COMFY_DIR="/root/comfyui" +COMFY_URL="http://127.0.0.1:8188" +WORKFLOW="${COMFY_DIR}/workflows/tile_detail.json" +PY="${COMFY_DIR}/venv/bin/python" + +[ -f "$IN" ] || { echo "ERROR: input not found: $IN" >&2; exit 1; } +[ -f "$WORKFLOW" ] || { echo "ERROR: workflow not found: $WORKFLOW" >&2; exit 1; } + +"$PY" - "$IN" "$OUT" "$DENOISE" "$WORKFLOW" "$COMFY_URL" "$COMFY_DIR" <<'PYEOF' +import sys, os, json, time, uuid, shutil, urllib.request, urllib.parse, mimetypes + +in_path, out_path, denoise, workflow_path, base, comfy_dir = sys.argv[1:8] +denoise = float(denoise) + +def http_json(path, data=None, headers=None): + url = base + path + req = urllib.request.Request(url, data=data, headers=headers or {}) + with urllib.request.urlopen(req, timeout=600) as r: + return json.loads(r.read().decode()) + +# 1. Upload input image to ComfyUI's input dir via /upload/image (multipart) +def upload_image(path): + fn = os.path.basename(path) + boundary = "----comfyboundary" + uuid.uuid4().hex + with open(path, "rb") as f: + content = f.read() + ctype = mimetypes.guess_type(path)[0] or "image/png" + parts = [] + def add(name, value, filename=None, is_file=False): + head = f'--{boundary}\r\nContent-Disposition: form-data; name="{name}"' + if filename: + head += f'; filename="{filename}"' + head += f'\r\nContent-Type: {ctype}' + head += "\r\n\r\n" + parts.append(head.encode() + (value if is_file else value.encode()) + b"\r\n") + add("image", content, filename=fn, is_file=True) + add("overwrite", "true") + body = b"".join(parts) + f"--{boundary}--\r\n".encode() + req = urllib.request.Request(base + "/upload/image", data=body, + headers={"Content-Type": f"multipart/form-data; boundary={boundary}"}) + with urllib.request.urlopen(req, timeout=120) as r: + resp = json.loads(r.read().decode()) + # returns {"name":..., "subfolder":..., "type":"input"} + return resp["name"] if not resp.get("subfolder") else f'{resp["subfolder"]}/{resp["name"]}' + +uploaded = upload_image(in_path) +print(f"[tile_detail] uploaded input as: {uploaded}") + +# 2. Load workflow, patch input filename + denoise +with open(workflow_path) as f: + wf = json.load(f) +patched = False +for nid, node in wf.items(): + if node.get("class_type") == "LoadImage": + node["inputs"]["image"] = uploaded + patched = True + if node.get("class_type") in ("UltimateSDUpscaleNoUpscale", "UltimateSDUpscale", "KSampler"): + node["inputs"]["denoise"] = denoise + # keep seam-fix denoise in step with the main pass when present + if "seam_fix_denoise" in node["inputs"]: + node["inputs"]["seam_fix_denoise"] = denoise +assert patched, "no LoadImage node found in workflow" + +client_id = uuid.uuid4().hex +payload = json.dumps({"prompt": wf, "client_id": client_id}).encode() +resp = http_json("/prompt", data=payload, headers={"Content-Type": "application/json"}) +prompt_id = resp["prompt_id"] +print(f"[tile_detail] queued prompt_id={prompt_id} denoise={denoise}") + +# 3. Poll /history/ until complete +t0 = time.time() +outputs = None +while True: + time.sleep(2) + hist = http_json(f"/history/{prompt_id}") + if prompt_id in hist: + entry = hist[prompt_id] + status = entry.get("status", {}) + if status.get("completed") or status.get("status_str") == "success": + outputs = entry.get("outputs", {}) + break + if status.get("status_str") == "error": + raise SystemExit(f"[tile_detail] ComfyUI reported error: {json.dumps(status)}") + if time.time() - t0 > 1800: + raise SystemExit("[tile_detail] timed out after 1800s") + +# 4. Locate the SaveImage output and copy to out_path +saved = None +for nid, out in (outputs or {}).items(): + for img in out.get("images", []): + if img.get("type") == "output": + saved = img + break + if saved: + break +assert saved, f"no output image in history: {json.dumps(outputs)[:500]}" + +src = os.path.join(comfy_dir, "output", saved.get("subfolder", ""), saved["filename"]) +shutil.copyfile(src, out_path) +print(f"[tile_detail] DONE in {time.time()-t0:.1f}s -> {out_path} (from {src})") +PYEOF diff --git a/tools/gex44-box/comfyui-detail-finisher/workflows/tile_detail.json b/tools/gex44-box/comfyui-detail-finisher/workflows/tile_detail.json new file mode 100644 index 00000000..1a02eac1 --- /dev/null +++ b/tools/gex44-box/comfyui-detail-finisher/workflows/tile_detail.json @@ -0,0 +1,76 @@ +{ + "1": { + "class_type": "CheckpointLoaderSimple", + "inputs": { "ckpt_name": "sd_xl_base_1.0.safetensors" } + }, + "2": { + "class_type": "LoadImage", + "inputs": { "image": "INPUT_IMAGE_PLACEHOLDER" } + }, + "3": { + "class_type": "CLIPTextEncode", + "inputs": { + "clip": ["1", 1], + "text": "masterpiece, highly detailed painterly game backdrop, crisp fine detail, sharp textures, intricate brushwork, high fidelity, detailed foliage and stonework, professional concept art" + } + }, + "4": { + "class_type": "CLIPTextEncode", + "inputs": { + "clip": ["1", 1], + "text": "blurry, low detail, jpeg artifacts, oversaturated, washed out, deformed, watermark, text, noise, smudge" + } + }, + "5": { + "class_type": "ControlNetLoader", + "inputs": { "control_net_name": "controlnet-tile-sdxl.safetensors" } + }, + "6": { + "class_type": "ControlNetApplyAdvanced", + "inputs": { + "positive": ["3", 0], + "negative": ["4", 0], + "control_net": ["5", 0], + "image": ["2", 0], + "strength": 0.75, + "start_percent": 0.0, + "end_percent": 1.0 + } + }, + "7": { + "class_type": "UltimateSDUpscaleNoUpscale", + "inputs": { + "upscaled_image": ["2", 0], + "model": ["1", 0], + "positive": ["6", 0], + "negative": ["6", 1], + "vae": ["1", 2], + "seed": 12345, + "steps": 24, + "cfg": 6.0, + "sampler_name": "dpmpp_2m", + "scheduler": "karras", + "denoise": 0.35, + "mode_type": "Linear", + "tile_width": 1024, + "tile_height": 1024, + "mask_blur": 8, + "tile_padding": 32, + "seam_fix_mode": "Band Pass", + "seam_fix_denoise": 0.35, + "seam_fix_width": 64, + "seam_fix_mask_blur": 8, + "seam_fix_padding": 16, + "force_uniform_tiles": true, + "tiled_decode": true, + "batch_size": 1 + } + }, + "8": { + "class_type": "SaveImage", + "inputs": { + "images": ["7", 0], + "filename_prefix": "tile_detail" + } + } +} diff --git a/tools/gex44-box/display-config/1440-fallback.Xresources b/tools/gex44-box/display-config/1440-fallback.Xresources new file mode 100644 index 00000000..718e95fb --- /dev/null +++ b/tools/gex44-box/display-config/1440-fallback.Xresources @@ -0,0 +1,6 @@ +Xft.dpi: 120 +Xft.antialias: true +Xft.hinting: true +Xft.hintstyle: hintslight +Xft.rgba: rgb +Xcursor.size: 32 diff --git a/tools/gex44-box/display-config/4k-readable.Xresources b/tools/gex44-box/display-config/4k-readable.Xresources new file mode 100644 index 00000000..fa62c4b2 --- /dev/null +++ b/tools/gex44-box/display-config/4k-readable.Xresources @@ -0,0 +1,6 @@ +Xft.dpi: 192 +Xft.antialias: true +Xft.hinting: true +Xft.hintstyle: hintslight +Xft.rgba: rgb +Xcursor.size: 48 diff --git a/tools/gex44-box/display-config/4k-workspace.Xresources b/tools/gex44-box/display-config/4k-workspace.Xresources new file mode 100644 index 00000000..72e48ab5 --- /dev/null +++ b/tools/gex44-box/display-config/4k-workspace.Xresources @@ -0,0 +1,6 @@ +Xft.dpi: 144 +Xft.antialias: true +Xft.hinting: true +Xft.hintstyle: hintslight +Xft.rgba: rgb +Xcursor.size: 40 diff --git a/tools/gex44-box/display-config/gex44-display-profile b/tools/gex44-box/display-config/gex44-display-profile new file mode 100755 index 00000000..f6509720 --- /dev/null +++ b/tools/gex44-box/display-config/gex44-display-profile @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +profile="${1:-4k-readable}" +export DISPLAY="${DISPLAY:-:0}" +export XAUTHORITY="${XAUTHORITY:-/home/unity/.Xauthority}" +export HOME="${HOME:-/home/unity}" + +case "$profile" in + 4k-readable) + mode="3840x2160R" + fallback_fb="3840x2160" + dpi="192" + resources="/home/unity/.config/gex44-display-profiles/4k-readable.Xresources" + ;; + 4k-workspace) + mode="3840x2160R" + fallback_fb="3840x2160" + dpi="144" + resources="/home/unity/.config/gex44-display-profiles/4k-workspace.Xresources" + ;; + 1440-fallback) + mode="2560x1440R" + fallback_fb="2560x1440" + dpi="120" + resources="/home/unity/.config/gex44-display-profiles/1440-fallback.Xresources" + ;; + *) + echo "Usage: gex44-display-profile [4k-readable|4k-workspace|1440-fallback]" >&2 + exit 64 + ;; +esac + +output="$(xrandr --query | awk '/ connected/{print $1; exit}')" + +if [[ -n "${output:-}" ]] && xrandr --query | grep -qE "(^| )${mode}( |$)"; then + xrandr --output "$output" --mode "$mode" --primary --dpi "$dpi" +else + xrandr --fb "$fallback_fb" --dpi "$dpi" +fi + +if [[ -f "$resources" ]]; then + xrdb -merge "$resources" +fi + +if command -v openbox >/dev/null 2>&1; then + openbox --reconfigure >/dev/null 2>&1 || true +fi + +xdpyinfo 2>/dev/null | grep -E 'dimensions|resolution' || true diff --git a/tools/gex44-box/display-config/gtk-settings.ini.4k-readable b/tools/gex44-box/display-config/gtk-settings.ini.4k-readable new file mode 100644 index 00000000..3332cb52 --- /dev/null +++ b/tools/gex44-box/display-config/gtk-settings.ini.4k-readable @@ -0,0 +1,8 @@ +[Settings] +gtk-font-name=Sans 16 +gtk-xft-antialias=1 +gtk-xft-hinting=1 +gtk-xft-hintstyle=hintslight +gtk-xft-rgba=rgb +gtk-xft-dpi=196608 +gtk-cursor-theme-size=48 diff --git a/tools/gex44-box/display-config/openbox-rc.xml.4k-readable b/tools/gex44-box/display-config/openbox-rc.xml.4k-readable new file mode 100644 index 00000000..38a030c0 --- /dev/null +++ b/tools/gex44-box/display-config/openbox-rc.xml.4k-readable @@ -0,0 +1,753 @@ + + + + + + + + 10 + 20 + + + + yes + + no + + yes + + no + + 200 + + no + + + + + Smart + +
yes
+ + Primary + + 1 + +
+ + + Clearlooks + NLIMC + + yes + yes + + sans + 16 + + bold + + normal + + + + sans + 16 + + bold + + normal + + + + sans + 18 + + normal + + normal + + + + sans + 18 + + normal + + normal + + + + sans + 16 + + bold + + normal + + + + sans + 16 + + bold + + normal + + + + + + + 4 + 1 + + + + 875 + + + + + yes + Nonpixel + + Center + + + + + 10 + + 10 + + + + + + + 0 + 0 + 0 + 0 + + + + TopLeft + + 0 + 0 + no + Above + + Vertical + + no + 300 + + 300 + + Middle + + + + + C-g + + + + leftno + + + rightno + + + upno + + + downno + + + leftno + + + rightno + + + upno + + + downno + + + 1 + + + 2 + + + 3 + + + 4 + + + + + + + + + + + + + + + + client-menu + + + + scrot -s + + + + + + + + + + + + + + + + + + + + + + + + yesyes + + + + + + + + + + + + right + + + + + left + + + + + up + + + + + down + + + + + + + + true + Konqueror + + kfmclient openProfile filemanagement + + + + + scrot + + + + + 1 + + 500 + + 400 + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + previous + + + next + + + previous + + + next + + + previous + + + next + + + + + + + + + + + + + + no + + + + + + + + + + + yes + + + + + + + + + + + + + + + + + + + + + + + + + client-menu + + + + + + top + + + + + + left + + + + + + right + + + + + + bottom + + + + + + client-menu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + client-menu + + + + + client-menu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + vertical + + + horizontal + + + + + + + + + + + + + + + + + previous + + + next + + + + previous + + + next + + + previous + + + next + + + + + + + + + + + + + + + + client-list-combined-menu + + + root-menu + + + + + + previous + + + next + + + previous + + + next + + + + + + + + + + /var/lib/openbox/debian-menu.xml + menu.xml + 200 + + no + + 100 + + 400 + + yes + + yes + + + + + + + +
diff --git a/tools/gex44-box/display-config/sunshine-apps.4k-readable.json b/tools/gex44-box/display-config/sunshine-apps.4k-readable.json new file mode 100644 index 00000000..bada6ad0 --- /dev/null +++ b/tools/gex44-box/display-config/sunshine-apps.4k-readable.json @@ -0,0 +1,50 @@ +{ + "env": { + "PATH": "$(PATH):$(HOME)/.local/bin" + }, + "apps": [ + { + "name": "Readable Desktop 4K", + "image-path": "desktop.png", + "prep-cmd": [ + { + "do": "/usr/local/bin/gex44-display-profile 4k-readable", + "undo": "/usr/local/bin/gex44-display-profile 4k-readable" + } + ] + }, + { + "name": "Workspace Desktop 4K", + "image-path": "desktop.png", + "prep-cmd": [ + { + "do": "/usr/local/bin/gex44-display-profile 4k-workspace", + "undo": "/usr/local/bin/gex44-display-profile 4k-readable" + } + ] + }, + { + "name": "Desktop", + "image-path": "desktop.png", + "prep-cmd": [ + { + "do": "/usr/local/bin/gex44-display-profile 4k-readable", + "undo": "/usr/local/bin/gex44-display-profile 4k-readable" + } + ] + }, + { + "name": "Steam Big Picture", + "detached": [ + "setsid steam steam://open/bigpicture" + ], + "prep-cmd": [ + { + "do": "/usr/local/bin/gex44-display-profile 4k-readable", + "undo": "setsid steam steam://close/bigpicture; /usr/local/bin/gex44-display-profile 4k-readable" + } + ], + "image-path": "steam.png" + } + ] +} diff --git a/tools/gex44-box/display-config/unity-desktop.sh.4k-readable b/tools/gex44-box/display-config/unity-desktop.sh.4k-readable new file mode 100755 index 00000000..3590f0a0 --- /dev/null +++ b/tools/gex44-box/display-config/unity-desktop.sh.4k-readable @@ -0,0 +1,21 @@ +#!/bin/bash +export DISPLAY=:0 +export HOME=/home/unity +export USER=unity +export LOGNAME=unity +export GEX44_DISPLAY_PROFILE="${GEX44_DISPLAY_PROFILE:-4k-readable}" +export GDK_SCALE=2 +export GDK_DPI_SCALE=1 +export GTK_SCALE=2 +export QT_SCALE_FACTOR=2 +export QT_AUTO_SCREEN_SCALE_FACTOR=0 +export ELECTRON_FORCE_DEVICE_SCALE_FACTOR=2 +export XCURSOR_SIZE=48 +export XFT_DPI=192 + +/usr/local/bin/gex44-display-profile "$GEX44_DISPLAY_PROFILE" >/home/unity/.gex44-display-profile.log 2>&1 || true + +pgrep -u unity openbox >/dev/null || (openbox &) +openbox --reconfigure >/dev/null 2>&1 || true + +exec x11vnc -display :0 -rfbauth /home/unity/.vnc/passwd -localhost -forever -shared -noxdamage -bg -o /home/unity/.vnc/x11vnc.log diff --git a/tools/gex44-box/display-config/xorg-service-4k-readable.conf b/tools/gex44-box/display-config/xorg-service-4k-readable.conf new file mode 100644 index 00000000..92cf1dcd --- /dev/null +++ b/tools/gex44-box/display-config/xorg-service-4k-readable.conf @@ -0,0 +1,3 @@ +[Service] +ExecStart= +ExecStart=/usr/bin/X :0 -ac -nolisten tcp -noreset -dpi 192 diff --git a/tools/gex44-box/display-config/xorg.conf.4k-readable b/tools/gex44-box/display-config/xorg.conf.4k-readable new file mode 100644 index 00000000..05b604b2 --- /dev/null +++ b/tools/gex44-box/display-config/xorg.conf.4k-readable @@ -0,0 +1,40 @@ +Section "ServerLayout" + Identifier "layout" + Screen 0 "nvidia" +EndSection + +Section "Monitor" + Identifier "GEX44Virtual4K" + VendorName "GEX44" + ModelName "Virtual 4K Readable" + HorizSync 30.0 - 140.0 + VertRefresh 50.0 - 75.0 + Option "DPMS" "false" + Modeline "3840x2160R" 533.00 3840 3888 3920 4000 2160 2163 2168 2222 +hsync -vsync + Modeline "2560x1440R" 241.50 2560 2608 2640 2720 1440 1443 1448 1481 +hsync -vsync + Modeline "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync +EndSection + +Section "Device" + Identifier "nvidia" + Driver "nvidia" + BusID "PCI:1:0:0" + Option "AllowEmptyInitialConfiguration" "true" + Option "HardDPMS" "false" + Option "ConnectedMonitor" "DFP-0" + Option "UseDisplayDevice" "DFP-0" + Option "ModeValidation" "NoEdidModes, NoMaxPClkCheck, NoEdidMaxPClkCheck, NoHorizSyncCheck, NoVertRefreshCheck, NoVirtualSizeCheck, AllowNonEdidModes" +EndSection + +Section "Screen" + Identifier "nvidia" + Device "nvidia" + Monitor "GEX44Virtual4K" + DefaultDepth 24 + Option "MetaModes" "DFP-0: 3840x2160R +0+0; DFP-0: 2560x1440R +0+0; DFP-0: 1920x1080_60.00 +0+0" + SubSection "Display" + Depth 24 + Modes "3840x2160R" "2560x1440R" "1920x1080_60.00" + Virtual 3840 2160 + EndSubSection +EndSection diff --git a/tools/gex44-box/ops/INSTALL.md b/tools/gex44-box/ops/INSTALL.md new file mode 100644 index 00000000..666cb36f --- /dev/null +++ b/tools/gex44-box/ops/INSTALL.md @@ -0,0 +1,139 @@ +# WorldOSPlayer — install & run + +## What is new in this build (FRESH CRYPT — brand-new crypt through the amended pipeline, rebuilt 2026-07-15) +- **The canonical crypt is now the brand-new `crypt_fresh_v1.png`** (#1565 / #1566, adopted at + neutral-anchor parity 7.0) — it replaces the earlier `crypt_armb_iter3_v1.png`. Dense authored + geometry: knotwork-carved pillars, a stone sarcophagus with a recumbent effigy, a carved altar, + arched wall alcoves, a lit wall torch, scattered bones + a funerary urn. +- **Paint == collision**: the engine walkslice grid was aligned to the fresh crypt geometry + (#1566, WALKSLICE-CRYPT-ALIGN) — what is painted is what collides; two walkable doorways, the + canonical props preserved. +- Data-only change: this build ships the new plate + updated `plates_manifest.json` + (`crypt -> plates/crypt_fresh_v1.png`). No client C# change since Box Cycle 1 + (`CombatSurfaceClient.cs` unchanged; the engine remains the sole writer). + +## What is new in this build (TAVERN-FIT2 adoption, the truthful tavern — rebuilt 2026-07-14) +- **The canonical tavern is now the density-law `fit2` plate** (`tavern_fit2_v1.png`, PR #1562, + playability-first ruling on #1557) — it replaces the earlier `tavern_truegrey_v1.png`. It is a + **truthful** room: **what is painted is what collides**. 14 authored collision props at + world-true scale (hearth, round tables, benches, barrels, crates, bar counter, stools, woodpile), + coherence-perfect (edge-recall 0.98, **zero invented furniture**), camera-fit extent. +- **Doorway painted at the authored (8,0)** — the tavern door is rendered in the plate at grid cell + **(8,0)**, matching the walkslice collision grid exactly, so the door affordance/glow sits on the + real painted opening (no phantom/mismatched door). +- Data-only change: this build ships the new plate + updated `plates_manifest.json` + (`tavern -> plates/tavern_fit2_v1.png`). No client C# change since M-ALIGN wave-1 + (`CombatSurfaceClient.cs` unchanged; the engine remains the sole writer). + +## What is new in this build (M-ALIGN wave-1, transition + navigation polish — rebuilt 2026-07-11) +- **No greybox flash / black gap on door-cross** (PR #1551, fixes #1544): crossing a door now reads + `old room -> black -> fade to finished new room`. An opaque black cover is raised the instant a + room change is detected, BEFORE the destination room's proxies/occluders rebuild behind it — so the + un-textured grey proxy boxes and the disconnected black frame the owner saw in playtest #8 are gone. +- **Rest-walk follows the engine path** (PR #1551): a rest-mode walk now glides along the engine's + authoritative route (parsed from the `walk_to_cell` response `path`) and routes **around** props + instead of straight-lining through tables/firepits ("walking through tables"). Combat glide + (`lastPath`) is byte-identical/unchanged. +- **Reciprocal-door arrivals** (PR #1550, engine-side): you now arrive at the door you came through — + the engine's arrival contract lands the party at the reciprocal door cell of the destination room. + This lives in the viewer/engine (NOT baked into this player build) — run the engine at the matching + main SHA for the reciprocal-door behavior. +- Client change is a pure consumer (`CombatSurfaceClient.cs`); the engine stays the sole writer. The + visual journey instrument (PR #1552) is a QA-side sweep, not part of the player — listed for context. + +## What is new in this build (SHIP-MORNING, three-room world + fire + tuned collision — rebuilt 2026-07-11) +- **Three-room world**: `crypt <-> camp_clearing_night <-> tavern` — the brand-new firelit tavern + (PR #1531 NEW-ROOM-TAVERN, epic #1508) now ships its own true-greybox plate + (`tavern_truegrey_v1.png`) alongside the existing crypt + camp rooms, registered in + `plates_manifest.json` (3 plate entries). This is the tavern's first-ever player render. +- **Fire**: the camp firepit's animated flame (VFX-ANCHORS) carries forward unchanged; the + tavern's hearth glow is painted into the plate for this build (an animated hearth fire is a + follow-up, mirroring the camp `effects` entry). +- **Tuned collision**: camp + crypt collision/walkability continue to reflect the true-greybox + geometry adopted in SHIP-CAMP/RING-COHESION; no collision regressions expected from adding the + tavern room (additive plate-registry entry only). + +## What is new in this build (VFX-ANCHORS, animated campfire — rebuilt 2026-07-11) +- The camp firepit now has an **animated fire** flickering over the painted pit + (`camp_clearing_night`, cell [5,8]) — a Synty painterly flame spawned by the new per-plate + **effects layer**. `plates_manifest.json` plate entries carry an optional `effects` array; + `effects_registry.json` maps each effect `type` to a prefab. Same mechanism is ready for + subtle embers/fireflies later (one manifest line). Pure presentation — no gameplay change; + a plate with no `effects` renders exactly as before. + +## What is new in this build (SHIP-CAMP, true-greybox camp plate — rebuilt 2026-07-11) +- `camp_clearing_night`'s backdrop now ships the **true-greybox** camp plate + (`camp_clearing_night_truegrey_v1.png`, PR #1518/#1519) instead of the legacy + `camp_clearing_night_v2.png` — correct-scale 3D-authored geometry (fixes the ~25% legacy + scale drift; fire pit shrunk from a 2x2 blob to the correct 2x1 ring) with paint registered + to that geometry, so collision/occlusion/scale for the camp room are right by construction. + Crypt is unchanged this build (`crypt_armb_iter3_v1.png`, iteration-2 restyle did not clear + the adopt gate — see #1518). + +## What is new in this build (ANIM-PACK, #1408 permanent T-pose fix — rebuilt 2026-07-11) +- All HUMANOID actors now play REAL animations from a shared humanoid AnimatorController + (Explosive LLC RPG Character Mecanim pack, retargeted): a live **idle**, a **walk/run** cycle + while gliding cell-to-cell, and **attack / hit-reaction / death** during combat — driven from + the engine surface (Speed float + Attack/Hit/Death triggers). No more T-posed/frozen actors. +- Non-humanoid rigs (giant_spider, dire_rat) and the generic hero template keep the prior + per-frame animation fallback automatically. + +# WorldOS Player — Walkable Slice (macOS) + +Universal macOS build (Intel + Apple Silicon), scene `M1CombatV1_canonical` with the +runtime plate registry + rest-stage actor rendering. + +This build ships the **owner playtest #4** fixes (PR #1505): +- **Crypt tomb footprint corrected** — the sarcophagus impassable footprint is now the coffin`s + actual FLOOR cells (cols2-7 x rows7-9), not its silhouette (the old cols3-9 x rows3-7 sat on the + open floor *behind* the coffin), so actors no longer stand on the painted tomb and the party + spawns on clear floor, not snug against it. +- **Door affordance** — door cells show a pulsing gold glow + a floating "To " label so you + can find how to change rooms. +- **Walkability overlay default-OFF** in normal play (a QA aid now); press **G** to toggle it, or + set `WORLDOS_WALK_OVERLAY=1`. + +## Requirements +- macOS (Intel or Apple Silicon). +- The WorldOS engine/viewer running locally, serving `/combat-surface` + `/move` for a campaign. +- Re-seed `walkslice_smoke01` from this build`s engine so the corrected crypt grid is served. + +## Run +1. Unzip `WorldOSPlayer.app.zip`. +2. Start the WorldOS viewer/engine for your campaign and note its base URL + (the walkable-slice smoke seeds `walkslice_smoke01`; the viewer typically listens on + `http://127.0.0.1:8790`). +3. Launch the player with the engine URL + campaign id via the launch-contract env vars + (read at startup by `CombatSurfaceClient.Start`): + + ```sh + WORLDOS_ENGINE_BASE_URL="http://127.0.0.1:8790" \ + WORLDOS_CAMPAIGN_ID="walkslice_smoke01" \ + WORLDOS_ONBOARD=1 \ + ./WorldOSPlayer.app/Contents/MacOS/WorldOSPlayer + ``` + + (Or export those three vars, then `open WorldOSPlayer.app`.) + +## What you`ll see (the walkable slice) +- Your party + the present NPC rendered as 3D actors — **idle + grounded** on the painterly plate, + on clear floor (never on the tomb or a pillar). +- **Click a floor cell** to walk your character (the actor glides there). +- **Click the NPC** to open a parley. +- **The glowing doorway** — click the pulsing gold door cell (labelled "To ") to cross to the + next location; the backdrop **plate swaps** (crypt -> campfire clearing) and the cast respawns. +- **Press `F`** to start a fight in place. +- **Press `G`** to toggle the walkability overlay (off by default in normal play). + +## Launch-contract env vars +| Var | Meaning | +|-----|---------| +| `WORLDOS_ENGINE_BASE_URL` | Engine/viewer base URL (**required**). | +| `WORLDOS_CAMPAIGN_ID` | Campaign to render (**required**). | +| `WORLDOS_ONBOARD=1` | Name plates + onboarding hint + door affordance (recommended for a first run). | +| `WORLDOS_WALK_OVERLAY=1` | Force the walkability grid overlay ON (QA/debug; default OFF). | +| `WORLDOS_PLAYTEST=1` | Playtest defaults (also enables the overlay). | + +## Gatekeeper +The app is unsigned. If macOS blocks it: right-click -> **Open**, or +`xattr -dr com.apple.quarantine WorldOSPlayer.app`. diff --git a/tools/gex44-box/ops/derive_gbuffer.py b/tools/gex44-box/ops/derive_gbuffer.py new file mode 100644 index 00000000..410117e4 --- /dev/null +++ b/tools/gex44-box/ops/derive_gbuffer.py @@ -0,0 +1,23 @@ +# Derive a depth + view-space normal map FROM an image (Depth-Anything-V2), matching the diffuse by construction +# → no structure-drift artifacts, works on a frame-filling high-Q diffuse. Output encoding matches WOSRelight.shader. +import sys, numpy as np +from PIL import Image +from transformers import pipeline +inp, out_depth, out_normal = sys.argv[1], sys.argv[2], sys.argv[3] +pipe = pipeline("depth-estimation", model="depth-anything/Depth-Anything-V2-Small-hf") +img = Image.open(inp).convert("RGB") +res = pipe(img) +d = np.array(res["depth"], dtype=np.float32) +d = (d - d.min()) / (d.max() - d.min() + 1e-6) # 0..1, near=1 (Depth-Anything: larger=closer) +# depth png (grayscale) — scaled so nearer=smaller lin (invert to match greybox LinDepth where near=small) +depth_lin = 1.0 - d # near -> small (matches greybox -view.z/80 near-small) +Image.fromarray((depth_lin*255).astype(np.uint8)).convert("RGB").save(out_depth) +# normal from depth gradient (Sobel-ish). z toward camera (view space), rgb = n*0.5+0.5 +gy, gx = np.gradient(d.astype(np.float32)) +STR = 6.0 +nx, ny, nz = -gx*STR, gy*STR, np.ones_like(d) +ln = np.sqrt(nx*nx + ny*ny + nz*nz) + 1e-6 +nx, ny, nz = nx/ln, ny/ln, nz/ln +nrm = np.stack([nx*0.5+0.5, ny*0.5+0.5, nz*0.5+0.5], axis=-1) +Image.fromarray((nrm*255).astype(np.uint8)).save(out_normal) +print("DERIVED", out_depth, out_normal, "shape", d.shape) diff --git a/tools/gex44-box/ops/launch_editor.sh b/tools/gex44-box/ops/launch_editor.sh new file mode 100755 index 00000000..09b04a8b --- /dev/null +++ b/tools/gex44-box/ops/launch_editor.sh @@ -0,0 +1,5 @@ +#!/bin/bash +export HOME=/home/unity DISPLAY=:0 XDG_RUNTIME_DIR=/tmp/runtime-unity +export PATH=/usr/local/bin:/usr/bin:/bin:/home/unity/.local/bin +cd /home/unity +exec /home/unity/Unity/Hub/Editor/6000.5.1f1/Editor/Unity -projectPath /home/unity/worldos-unity diff --git a/tools/gex44-box/ops/setup_depth.sh b/tools/gex44-box/ops/setup_depth.sh new file mode 100644 index 00000000..ace147a0 --- /dev/null +++ b/tools/gex44-box/ops/setup_depth.sh @@ -0,0 +1,6 @@ +set -e +python3 -m venv /root/depth_env +/root/depth_env/bin/pip install --quiet --upgrade pip +/root/depth_env/bin/pip install --quiet torch --index-url https://download.pytorch.org/whl/cu121 +/root/depth_env/bin/pip install --quiet transformers pillow numpy +/root/depth_env/bin/python -c "from transformers import pipeline; pipeline(\"depth-estimation\", model=\"depth-anything/Depth-Anything-V2-Small-hf\"); print(\"DEPTH_ANYTHING_READY\")" diff --git a/tools/gex44-box/ops/worldos-unity-save.sh b/tools/gex44-box/ops/worldos-unity-save.sh new file mode 100755 index 00000000..5c2b5dff --- /dev/null +++ b/tools/gex44-box/ops/worldos-unity-save.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# WorldOS Unity project autosave (owner-requested 2026-07-16). Primary save = LOCAL git commit +# (survives independent of GitHub quota/auth). GitHub push is BEST-EFFORT (starts working the +# moment LFS quota + creds are green). Runs as the unity user via cron. +# worldos-unity-save.sh -> commit-if-dirty only (frequent) +# worldos-unity-save.sh --push -> commit + best-effort LFS push (daily) +set -uo pipefail +export HOME=/home/unity +cd /home/unity/worldos-unity || exit 1 +LOG=/home/unity/worldos-autosave.log +ts() { date -u +%FT%TZ; } +# Don't capture a mid-write tree: if any source file changed in the last 90s, Unity may be writing. +if find Assets Packages ProjectSettings -type f -newermt '-90 seconds' 2>/dev/null | head -1 | grep -q .; then + echo "$(ts) skip: source modified <90s ago (Unity may be mid-write)" >>"$LOG"; exit 0 +fi +if [ -z "$(git status --porcelain)" ]; then + echo "$(ts) clean: nothing to save" >>"$LOG"; exit 0 +fi +git add -A +git commit -q -m "autosave $(ts): working-tree checkpoint" && echo "$(ts) committed locally" >>"$LOG" +if [ "${1:-}" = "--push" ]; then + if git push origin main >>"$LOG" 2>&1; then echo "$(ts) pushed to GitHub" >>"$LOG" + else echo "$(ts) push FAILED (LFS quota/creds?) — LOCAL COMMIT IS SAFE" >>"$LOG"; fi +fi