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
Update 8 file(s)
8 files changed
+100−23
BRIDGE_VERSION+1−1@@ -1 +1 @@-1.9.80+1.9.81
adom-bridge-fusion-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "fusion360",- "version": "1.9.80",- "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.92/adom-bridge-fusion-v1.9.80.zip",- "sha256": "976127b414acfdb036046e11b5b0488b0e9eec5d2c374d7fd0ca258d3dd24ef7",- "size": 420002,+ "version": "1.9.81",+ "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.93/adom-bridge-fusion-v1.9.81.zip",+ "sha256": "00661fd66efb0b3d033982d2d8cedbe5350f4a1dba22fc7270ae6c261ee8eeb2",+ "size": 420956, "verbPrefixes": [ "fusion_" ],
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "fusion360", "displayName": "Autodesk Fusion 360",- "version": "1.9.80",+ "version": "1.9.81", "description": "Drive Autodesk Fusion 360 from the cloud: launch Fusion, electronics board layout, design rules, exports (STEP/IGES/STL/3MF/USDZ/OBJ/DXF/DWG/Gerbers/BOM/CPL), fast APS server-indexed cloud search plus browse/recent/file-info/versions, cloud file download/upload and folder creation, and in-app parametric modeling (fusion_run_modeling_script). Never-charge: APS calls are capped to the free tier.", "homepage": "https://wiki.adom.inc/adom/fusion-bridge", "author": "Adom Inc.",
dashboard/Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "fusion-dashboard"-version = "1.9.92"+version = "1.9.93" edition = "2021" [dependencies]
handlers/fusion_ui.py+80−6@@ -11,6 +11,7 @@ import ctypes import ctypes.wintypes import os import struct+import subprocess import time # Guard windll so the module imports on non-Windows hosts (the bridge must boot@@ -138,14 +139,74 @@ def _send_input(*inputs): # --- Window finding --- -def _find_fusion_hwnd() -> int:- """Find Fusion 360's MAIN window: the LARGEST visible window titled 'Autodesk Fusion'.+def _fusion_window_pids() -> set:+ """PIDs of running Fusion360.exe processes, for title-independent window matching."""+ try:+ out = subprocess.check_output(+ ["tasklist", "/FI", "IMAGENAME eq Fusion360.exe", "/FO", "CSV", "/NH"],+ stdin=subprocess.DEVNULL, stderr=subprocess.DEVNULL, text=True, timeout=5,+ creationflags=(subprocess.CREATE_NO_WINDOW+ if hasattr(subprocess, "CREATE_NO_WINDOW") else 0))+ except Exception:+ return set()+ pids = set()+ for line in out.splitlines():+ parts = [p.strip('"') for p in line.split('","')]+ if len(parts) > 1:+ try:+ pids.add(int(parts[1]))+ except Exception:+ pass+ return pids - First-match was wrong (2026-08-15, caught by the demo tour's gallery): Fusion keeps- tiny helper/ghost windows carrying the same title, and when one enumerates first the- 'screenshot' is a 236px title-bar sliver. The real main window is always the largest- match by area, so pick that.++def _find_fusion_hwnd() -> int:+ """Find Fusion 360's MAIN window: the LARGEST visible window OWNED BY A FUSION PROCESS.++ Two generations of this bug, both producing a 237x39 title-bar sliver instead of the+ app:+ 1. first-match (fixed 2026-08-15) - Fusion keeps tiny helper/ghost windows carrying+ the same title, and one of them enumerated first.+ 2. TITLE-match (fixed 2026-08-19) - picking the largest window *titled* "Autodesk+ Fusion" still fails whenever the main window is mid-transition and does not carry+ that title, leaving the sliver as the only match. The 8/8 surfaces pass caught it:+ the library surface returned a 237x39 capture while every other surface returned+ 1568x940.+ Ownership by PID is title-independent, so a retitled or transitioning main window can+ no longer be lost. Title matching stays as the fallback for the case where the process+ list is unreadable. """+ pids = _fusion_window_pids()+ if pids:+ best_pid = [0, 0]++ WNDENUMPROC_P = ctypes.WINFUNCTYPE(+ ctypes.c_bool, ctypes.wintypes.HWND, ctypes.wintypes.LPARAM+ )++ def cb_pid(hwnd, _lparam):+ if user32.IsWindowVisible(hwnd):+ pid = ctypes.wintypes.DWORD()+ user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid))+ if pid.value in pids:+ try:+ l, t, r, b = _get_window_rect(hwnd)+ area = max(0, r - l) * max(0, b - t)+ except Exception:+ area = 0+ if area > best_pid[1]:+ best_pid[0], best_pid[1] = hwnd, area+ return True++ cbp = WNDENUMPROC_P(cb_pid)+ _callbacks.append(cbp)+ user32.EnumWindows(cbp, 0)+ _callbacks.remove(cbp)+ # Require something PLAUSIBLY the app, not a toast/sliver: anything under+ # 400x300 is not Fusion's main window, so fall through to the title pass.+ if best_pid[0] and best_pid[1] >= 400 * 300:+ return best_pid[0]+ best = [0, 0] # hwnd, area WNDENUMPROC = ctypes.WINFUNCTYPE( ctypes.c_bool, ctypes.wintypes.HWND, ctypes.wintypes.LPARAM@@ -417,6 +478,19 @@ def screenshot_fusion_window(use_bitblt: bool = False) -> dict: if width <= 0 or height <= 0: return {"success": False, "error": f"Invalid window rect: {left},{top},{right},{bottom}"} + # A SLIVER IS NOT EVIDENCE (2026-08-19). If the only window we could find is+ # smaller than the app could possibly be, the main window is mid-transition -+ # wait briefly and re-resolve rather than returning a 237x39 title-bar strip+ # that a caller will happily render as "the library surface, captured".+ if width < 400 or height < 300:+ time.sleep(2.5)+ hwnd2 = _find_fusion_hwnd()+ if hwnd2:+ l2, t2, r2, b2 = _get_window_rect(hwnd2)+ if (r2 - l2) >= 400 and (b2 - t2) >= 300:+ hwnd, left, top, right, bottom = hwnd2, l2, t2, r2, b2+ width, height = right - left, bottom - top+ if use_bitblt: # Screen DC capture — needs foreground SW_RESTORE = 9
install.sh+1−1@@ -21,7 +21,7 @@ echo "Installed fusion-bridge skills: $(ls "$PKG_DIR/skills" 2>/dev/null | tr '\ # binary (the three-artifact pattern: bridge zip -> ab, THIS pkg -> container skills + # this download, page media -> wiki). Per the wiki's PKG_VS_RELEASE policy, binaries are # platform-tagged RELEASE assets, never tarball content - the installer fetches them.-DASH_VERSION="1.9.92"+DASH_VERSION="1.9.93" DASH_URL="https://wiki.adom.inc/download/adom/fusion-bridge/${DASH_VERSION}/fusion-dashboard" DEST="" if [ -w /usr/local/bin ]; then DEST=/usr/local/bin
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "fusion-bridge",- "version": "1.9.92",+ "version": "1.9.93", "type": "app", "description": "This package installs the bridge's SKILLS into your container so your AI knows how to drive it; Adom Bridge loads the bridge runtime itself from the release zip.", "dependencies": {
page.json+11−8@@ -1,16 +1,20 @@ { "slug": "fusion-bridge",- "version": "1.9.92",+ "version": "1.9.93", "type": "app", "description": "This package installs the bridge's SKILLS into your container so your AI knows how to drive it; Adom Bridge loads the bridge runtime itself from the release zip.", "dependencies": {- "adom/adom-desktop": "*"+ "adom/adom-desktop": "^1.9.0" }, "scripts": { "install": "./install.sh", "uninstall": "./uninstall.sh" }, "tags": [+ "ab",+ "bridge",+ "fusion",+ "desktop-app", "fusion360", "autodesk", "cad",@@ -70,7 +74,10 @@ "build a basic parts library", "add a 3d model to a component", "make a fusion 360 library with 3d",- "set up the fusion bridge"+ "set up the fusion bridge",+ "fusion dashboard",+ "fusion status page",+ "open the fusion launch page" ], "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.",@@ -99,9 +106,5 @@ "label": "Part volume", "prompt": "How much material does each printed part in this assembly use?" }- ],- "author": {- "name": "John Lauer",- "email": "[email protected]"- }+ ] }