#!/usr/bin/env python3 """Eyes-on shots at the two REPORTED defects (not generic beauty angles). Targets: A entry ramp start (-4122, 47, -7860) -- the 390-stud access gap B exit ramp start (-4258, 47, -7836) C mainline junction (-3700, 102, -7184) -- the dY -6.0 step D ramp vs nearest building(-4419, 223, -6751) """ import shutil import sys import time sys.path.insert(0, "/tmp") import rbx # noqa: E402 OUT = "/home/jesse/roblox/tokyo-wangan-racing/tools/shots" SHOTS = [ # name, camera pos, look-at ("D1_entry_ramp_start", (-4122 + 210, 47 + 120, -7860 + 210), (-4122, 47, -7860)), ("D2_entry_start_low", (-4122 + 70, 47 + 25, -7860 + 70), (-4122, 55, -7860)), ("D3_exit_ramp_start", (-4258 - 200, 47 + 110, -7836 + 200), (-4258, 47, -7836)), ("D4_junction_step", (-3700 + 190, 102 + 90, -7184 + 190), (-3700, 102, -7184)), ("D5_ramp_vs_building", (-4419 + 520, 223 + 180, -6751 + 520), (-4300, 120, -7100)), ("D6_corridor_along", (-4122, 47 + 260, -7860 + 480), (-4300, 110, -7200)), ] CAM = """ 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 "ok" """ def main(): made = [] for name, (px, py, pz), (tx, ty, tz) in SHOTS: fov = 70 if "low" in name or "along" in name else 55 r = rbx.call( "execute_luau", { "datamodel_type": "Edit", "code": CAM.format( fov=fov, px=px, py=py, pz=pz, tx=tx, ty=ty, tz=tz ), }, wait=12, timeout=300, ) if isinstance(r, dict) and r.get("isError"): print(f"{name}: CAM FAIL {str(r)[:120]}") 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)[:140]}") continue dest = f"{OUT}/{name}.jpg" shutil.copy(imgs[0], dest) made.append(dest) print(f"{name}: OK -> {dest}") print(f"\nMADE {len(made)}") if __name__ == "__main__": main()