SCENEGOD/CLAUDE.md
type-two 128e24a7cb [deploy] digalot.fyi hosting: prefix-agnostic frontend, ship-check hardening, docker+nginx kit
- web: all URLs relative (imports ./web/..., fetches assets/...) so the app
  serves at / locally and under /scenegod/ behind nginx; esc() on dock
  innerHTML interpolations (ship-check XSS class)
- server: capped_body on every POST (scenes 5MB, frames 25MB, meta/director
  256KB-1MB), render begin sanity (fps<=60, dims<=4096, frame idx<=20000)
- deploy/: Dockerfile (slim+ffmpeg), compose (project 'scenegod' — avoids
  the shared-'deploy'-project orphan trap with meshgod), nginx location
  (suite basic-auth), deploy.sh (rsync model, meshgod-style)
- live: digalot.fyi/scenegod/ -> 401 unauthed, app healthy on dealgod_default

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 02:43:26 +10:00

5.0 KiB

SCENEGOD — machinima director's sandbox (iClone/SFM UX, GODVERSE stack)

Drop characters + animation clips + image backdrops on a 3D stage, keyframe transforms/cameras/lights on a timeline, render mp4. Web app: FastAPI + three.js, same conventions as MESHGOD (~/Documents/MESHGOD).

Deploy model (digalot.fyi suite)

  • Prod: dealgod VPS root@100.94.195.115, /opt/scenegod — NOT a git checkout: ./deploy/deploy.sh rsyncs from a dev Mac and rebuilds (deploy/docker-compose.yml, project name scenegod — do NOT drop the name: key; meshgod+scenegod both compose from dirs called "deploy" and would otherwise share a project and orphan each other). Container joins the external dealgod_default net; data volumes under /opt/scenegod-data/.
  • nginx: deploy/nginx-scenegod.conf block lives in the digalot.fyi server in /opt/dealgod/nginx/dealgod-servers.conf (dealgod-nginx container) — suite basic-auth (meshgod.htpasswd). Live: digalot.fyi/scenegod/.
  • Frontend is PREFIX-AGNOSTIC: all web URLs are relative (module imports ./web/..., fetches assets/...) so the app works at / locally AND under /scenegod/. Never reintroduce a leading / in a web-side URL.
  • VPS env keeps SCENEGOD_LLM_URL/SCENEGOD_MB UNSET (features 503/hide; they shell to tailnet boxes — ultra-only). rhubarb not in the image.
  • Server has ship-check hardening: capped_body on every POST (frames 25MB, scenes 5MB), render dims ≤4096/fps ≤60/frame index ≤20000, esc() on all dock innerHTML interpolations. Keep new endpoints behind the same rules.

You are one of THREE parallel lane agents

  1. Read, in order: this file → PLAN.md → your lane file in lanes/ → your log in logs/. Your lane file is your source of truth — the orchestrator (Fable) updates it between your sessions. Re-read it at the start of EVERY session; instructions may have changed since your last one.

  2. Only touch files your lane owns (ownership map in PLAN.md §3). If you need a change in another lane's file, write the request in your log under BLOCKED/REQUESTS — do not edit it yourself.

  3. Log protocol — append (never rewrite) to logs/lane<X>.md at the end of every session, and mid-session when you make a design decision:

    ## 2026-07-18 session N
    DONE: what shipped, with file:line pointers
    DECISIONS: choices made + why (schema tweaks, deps, algorithms)
    BLOCKED/REQUESTS: what you need from another lane or the orchestrator
    NEXT: what you'd do next session
    
  4. Commit early, commit often, on main, prefixed [laneA]/[laneB]/ [laneC]. git pull --rebase before every commit — other lanes commit to the same branch. File ownership makes conflicts near-zero; if you hit one anyway, resolve only your own files and log it. Stage your own files explicitly (git add <paths>) — never git add -A/.: another lane's uncommitted work may be sitting in the shared working dir, and -A sweeps it into your commit (happened once; attribution mess).

  5. Don't exceed your lane's current milestone. Milestones and sync points are in PLAN.md §5. Finishing early = polish + tests + log, not starting the next milestone uninvited.

Stack rules

  • Python 3.11 stdlib + fastapi + uvicorn only (requirements.txt). No other server deps without logging a REQUEST first.
  • Frontend: vanilla ES modules + three.js via importmap (copy the pattern from /Users/johnking/Documents/MESHGOD/meshgod/web/rigroom.html). No bundler, no npm, no framework.
  • Server: uvicorn scenegod.server:app --port 8020, binds 127.0.0.1 by default (local tool on ultra; VPS deploy is a later problem).
  • Secrets/env in .env (gitignored). Never commit tokens.
  • Reference code you may READ (never edit): the MESHGOD repo, especially meshgod/web/rigroom.html (retarget bake), meshgod/library.py (folder scanning), meshgod/ops.py (MODELBEAST submit contract), scripts/glb2fbx.py (headless Blender pattern).

Gotchas inherited from MESHGOD (learned the hard way — do not relearn)

  • trimesh/some GLBs omit metallicFactor → glTF default 1.0 → renders black. Viewer must use an IBL environment (RoomEnvironment + PMREM), not just lights.
  • Serve HTML no-cache — a stale cache once hid UI buttons for a day.
  • Mixamo rig quirks (all already solved in rigroom's bakeRetarget — port, don't reinvent): namespaces differ per download (mixamorig4Hips), FBX files carry duplicate hierarchies, quaternion sign continuity must be enforced, Blender-exported GLB rest poses differ from FBX rests → retarget = world-space rotation-delta bake at 30fps, never raw track copy.
  • Rigged GLBs must NEVER be sent through any Blender join/decimate "finish" path — it spawns phantom joint meshes and mauls the armature.
  • Path traversal: every endpoint that takes a path must resolve + verify it stays inside its root (ship-check rule).
  • Verbose commands (installs, test runs, ffmpeg): pipe through | lm -l 2.