app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
← Commit history
Publish 1.9.244
3 files changed
+60−11
.release-page-head+1−1@@ -1 +1 @@-4a6ba8d45583b875254cf75fcb6de39039e54d26+d43a384ff56772a655266e58a5d401f68268e13e
page.json+7−10@@ -11,10 +11,6 @@ "uninstall": "./uninstall.sh" }, "tags": [- "ab",- "bridge",- "fusion",- "desktop-app", "fusion360", "autodesk", "cad",@@ -79,10 +75,7 @@ "build a basic parts library", "add a 3d model to a component", "make a fusion 360 library with 3d",- "set up the fusion bridge",- "fusion dashboard",- "fusion status page",- "open the fusion launch page"+ "set up the fusion bridge" ], "discovery_pitch": "Use the Adom Bridge Fusion 360 bridge when the user wants to DRIVE Autodesk Fusion 360 from the cloud: open/search their team's Fusion cloud designs, lay out a PCB or do electronics, export STEP/IGES/STL/Gerbers/BOM, or build a component library with real rendering 3D. It runs Fusion on the user's own machine via Adom Bridge. NOT for web/browser/login/form-filling (that's the native-browser extension) and NOT for KiCad (that's the kicad bridge).", "brief": "Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.",@@ -111,5 +104,9 @@ "label": "Part volume", "prompt": "How much material does each printed part in this assembly use?" }- ]-}+ ],+ "author": {+ "name": "John Lauer",+ "email": "[email protected]"+ }+}
tools/live_feed_drain.pyadded+52@@ -0,0 +1,52 @@+#!/usr/bin/env python3+"""Drain fusion_live_feed's box-side ring buffer into shotlog, from the container.++ python3 tools/live_feed_drain.py --target AdomLapper --channel fusion-live [--interval 1.0]++Publishes each frame with a kind tag so a viewer never confuses them:+ [main #n] the Fusion window each tick (the ~1 fps video)+ [popup #n.m] each owned dialog/panel over it, tied to its tick+Proof frames are NOT here; they come from fusion_prove_result evidence[] (kind:proof).+"""+import argparse, json, subprocess, sys, time, os, base64++def ab(target, verb, args):+ p = subprocess.run(["adom-bridge", "--ai-thread", "fusion-live-feed", "--target", target, verb, json.dumps(args)],+ capture_output=True, text=True, timeout=90)+ try:+ d = json.loads(p.stdout); x = d.get("data") or d+ if isinstance(x.get("output"), str):+ try: x = json.loads(x["output"])+ except Exception: pass+ return x+ except Exception:+ return {}++def main():+ a = argparse.ArgumentParser(); a.add_argument("--target", required=True); a.add_argument("--channel", default="fusion-live")+ a.add_argument("--interval", type=float, default=1.0); a.add_argument("--max-sec", type=float, default=600)+ o = a.parse_args()+ st = ab(o.target, "fusion_live_feed", {"action": "start", "intervalSec": o.interval, "maxSec": o.max_sec})+ print("feed:", "started" if st.get("started") else ("already running" if st.get("alreadyRunning") else st))+ since, t0, pushed = 0, time.time(), 0+ os.makedirs("/tmp/live_feed", exist_ok=True)+ while time.time() - t0 < o.max_sec:+ r = ab(o.target, "fusion_live_feed", {"action": "frames", "since": since})+ for f in r.get("frames") or []:+ since = max(since, f["tick"])+ rf = ab(o.target, "read_file", {"path": f["path"], "encoding": "base64"})+ c = rf.get("content") or ""+ if not c: continue+ local = "/tmp/live_feed/%s_%d_%s.png" % (f["kind"], f["tick"], f.get("index", 0))+ try: open(local, "wb").write(base64.b64decode(c))+ except Exception: continue+ desc = ("[main #%d] %s | %d popup(s)" % (f["tick"], f.get("title", ""), f.get("popups", 0)) if f["kind"] == "main"+ else "[popup #%d.%d] %s" % (f["tick"], f.get("index", 0), f.get("title", "")))+ subprocess.run(["adom-shotlog", "inject", "-c", o.channel, "-d", desc, "-s", "desktop_screenshot_window", "--native", local],+ capture_output=True, text=True, timeout=30)+ pushed += 1+ if not r.get("running") and since: print("feed ended; pushed", pushed); break+ time.sleep(o.interval)+ ab(o.target, "fusion_live_feed", {"action": "stop"})++if __name__ == "__main__": main()