tools: viewport capture + cache-bust rebuild harness

screen_capture DOES work via the bridge (capture_id='ScreenCapture_1');
the prior assumption that the Studio viewport couldn't be captured from
this box was wrong. capture_shots.py sets the Edit camera per shot and
pulls a jpg for each angle.

rebuild_cachebust.luau documents the require() cache trap: pushing new
.Source does not invalidate the per-instance module cache, so a rebuild
silently runs the OLD code and the diagnostic reports already-fixed
failures. Swapping in Clone()s at the same paths forces a fresh compile.
This commit is contained in:
2026-08-02 16:30:20 -04:00
parent c8dabea53a
commit 6b0e3b75e4
2 changed files with 81 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env python3
"""Capture a set of Studio viewport angles of the Daikoku PA junction.
Sets the Edit-mode camera via execute_luau, then pulls a screen_capture for
each shot. Bridge calls are slow (~30-60s each), so this runs as one batch.
NOTE (corrects an old assumption): screen_capture DOES work on this setup.
It needs capture_id='ScreenCapture_1'. Earlier notes claimed the Studio
viewport could not be screenshotted from wks-victus -- that was wrong.
"""
import shutil
import sys
import time
sys.path.insert(0, "/tmp")
import rbx # noqa: E402
OUT = "/home/jesse/roblox/tokyo-wangan-racing/tools/shots"
# PA centre measured from the built parts.
CX, CY, CZ = -4116, 51, -7479
SHOTS = [
# name, camera offset from PA centre, look-at offset
("01_overview_oblique", (520, 340, 520), (0, 0, 0)),
("02_top_down", (5, 900, 5), (0, 0, 0)),
("03_underneath_clearance", (330, 20, 300), (0, 30, 0)),
("04_onramp_low", (-250, 70, 60), (60, 20, -40)),
("05_offramp_low", (300, 75, -160), (-60, 20, 40)),
("06_section_side", (900, 120, 40), (0, 25, 0)),
]
CAM_TPL = """
local cam = workspace.CurrentCamera
cam.CameraType = Enum.CameraType.Scriptable
cam.FieldOfView = {fov}
cam.CFrame = CFrame.lookAt(
Vector3.new({px}, {py}, {pz}),
Vector3.new({tx}, {ty}, {tz})
)
return "cam ok"
"""
def main():
made = []
for name, (ox, oy, oz), (tx, ty, tz) in SHOTS:
fov = 55 if "top_down" not in name else 40
code = CAM_TPL.format(
fov=fov,
px=CX + ox,
py=CY + oy,
pz=CZ + oz,
tx=CX + tx,
ty=CY + ty,
tz=CZ + tz,
)
r = rbx.call("execute_luau", {"datamodel_type": "Edit", "code": code})
if isinstance(r, dict) and r.get("isError"):
print(f"{name}: CAM FAIL {r}")
continue
time.sleep(1.5)
cap = rbx.call(
"screen_capture", {"capture_id": "ScreenCapture_1"}, wait=22, timeout=300
)
imgs = cap.get("images") if isinstance(cap, dict) else None
if not imgs:
print(f"{name}: CAPTURE FAIL {str(cap)[:160]}")
continue
dest = f"{OUT}/{name}.jpg"
shutil.copy(imgs[0], dest)
made.append(dest)
print(f"{name}: OK -> {dest}")
print("\nMADE " + str(len(made)) + " shots")
for m in made:
print(m)
if __name__ == "__main__":
main()