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 101 file(s)
19 files changed
+208−20
BRIDGE_VERSION+1−1README.md+1adom-bridge-fusion-manifest.json+4−4bridge.json+1−1dashboard/Cargo.lock+1−1dashboard/Cargo.toml+1−1docs/MULTIPART_LIBRARY_IMPORT.md+147docs/img/multipart/banner-in-package3d-generator.pngdocs/img/multipart/library-three-parts-ganged.pngdocs/img/multipart/own-footprint-tps54427ddar.pngdocs/img/multipart/quick-actions-live-view.pngdocs/img/multipart/quick-actions-multi-pick.pngdocs/img/multipart/wrong-footprint-tps54427ddar.pnginstall.sh+1−1package.json+1−1page.json+11−8server.py+31skills/fusion-multipart-libraries/SKILL.md+5−1tools/release.sh+3−1BRIDGE_VERSION+1−1@@ -1 +1 @@-1.9.263+1.9.264
README.md+1@@ -23,6 +23,7 @@ Short version below, full detail in each guide. | [2D board layout](docs/board-layout-2d.md) | PCB editor, design rules, layer + stackup discovery, routing, and gerbers/BOM/CPL for the fab. | | [3D view, export and STEP colorization](docs/3d-viewer-and-export.md) | The 3D PCB, every export format, web-grade GLB (16 MB to ~465 KB), and recoloring a grey imported STEP. | | [Electronics library manager](docs/electronics-libraries.md) | Symbols, IPC footprints and real 3D packages, generated rather than hand-drawn, plus how to verify a part before shipping it. |+| [Multi-part library import](docs/MULTIPART_LIBRARY_IMPORT.md) | How a zip of `.lbr` + STEPs becomes a Library Manager library with rendering 3D on every part: cloud `.f3d` urns, per-part minting (and the wrong-footprint trap it avoids), proof, and what the user sees. With screenshots. | | [Mechanical BOM and physical properties](docs/mechanical-bom.md) | Kit-aware assembly BOM that matches Fusion's Manage to BOM, and per-part volume/mass for costing. | | [Sign-in, sessions and updates](docs/sign-in-and-updates.md) | Multi-profile Autodesk sign-in, SSO without passwords, one login covering APS, and silent auto-updates. | | [Autodesk's Fusion MCP server](docs/fusion-mcp-server.md) | Proxy Autodesk + Anthropic's local MCP server (text-to-CAD, Electronics object model) so a cloud AI can reach it, and turn it on for the user. |
adom-bridge-fusion-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "fusion360",- "version": "1.9.263",- "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.263/adom-bridge-fusion-v1.9.263.zip",- "sha256": "67b364b0418e02b31bf1fb282b3363f5fd351b0c0a27592f074d2ebd6f69cf07",- "size": 556122,+ "version": "1.9.264",+ "url": "https://wiki.adom.inc/download/adom/fusion-bridge/1.9.264/adom-bridge-fusion-v1.9.264.zip",+ "sha256": "bcd6148e63c31ec87e58fc1da5fe2d525efda3113347bfaa27aa282686c9f6f9",+ "size": 556647, "verbPrefixes": [ "fusion_" ],
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "fusion360", "displayName": "Autodesk Fusion 360",- "version": "1.9.263",+ "version": "1.9.264", "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.lock+1−1@@ -4,7 +4,7 @@ version = 4 [[package]] name = "fusion-dashboard"-version = "1.9.263"+version = "1.9.264" dependencies = [ "serde_json", ]
dashboard/Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "fusion-dashboard"-version = "1.9.263"+version = "1.9.264" edition = "2021" [dependencies]
docs/MULTIPART_LIBRARY_IMPORT.mdadded+147@@ -0,0 +1,147 @@+# Multi-part library import: how a Fusion library gets real, rendering 3D on every part++This is the technical account of what `fusion_install_library_bundle` does between "a zip of+`.lbr` + `.step` files" and "a library in your Fusion Library Manager where every package+renders its chip on its own footprint". It exists because the middle of that sentence is+where Fusion makes things hard, and because two of the ways to get it subtly wrong were+found on real runs and are pictured below.++If you only want to use it: press **Create Fusion library** on a wiki part page (or several+parts on the Quick Actions page), and the bridge does everything here. If you are debugging+it, extending it, or wondering why your chip sits on the wrong pads, read on.++## The problem Fusion sets++An EAGLE/Fusion library (`.lbr`) describes symbols, footprints (packages) and devicesets in+XML. A footprint can carry a **3D package**, but the 3D package is not in the XML. It is a+reference to a **Fusion cloud design**, addressed by a **urn**:++```xml+<packages3d>+ <package3d name="TPS54427DDAR" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.AbCd...?version=1"+ locally_modified="yes" type="model">+ <packageinstances><packageinstance name="TPS54427DDAR"/></packageinstances>+ </package3d>+</packages3d>+...+<device name="" package="TPS54427DDAR">+ <connects>...</connects>+ <package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.AbCd...?version=1"/></package3dinstances>+ <technologies>...</technologies>+</device>+```++Three facts drive the whole design:++1. **Only a Fusion design renders.** Upload a raw STEP to the cloud and bind its urn: the+ reference resolves, the library opens, and the 3D preview says "Thumbnail download+ failed". A `.f3d` (a real Fusion design with the STEP imported into it) binds and renders+ exactly like a package minted by hand in the GUI.+2. **The GUI way is dialog-trapped.** Fusion's Package3D generator ends with FINISH, which+ pops a native Save dialog and two Chromium modals that no automation can read or dismiss+ in the background. So the bridge never presses FINISH.+3. **The generator loads the first package of the open library**, whatever path you hand+ the command. This one is the trap pictured below.++## What one part goes through (the "mint")++```+per-part .lbr --open--> library active+ --Electron.Create3DPackage--> generator document, footprint (pads + courtyard) loaded+ --importToTarget(STEP)--> chip placed exactly as the STEP was published+ --doc.saveAs(<pkg>_3d)--> cloud design in Adom AI Workspace/<library>/ (no FINISH)+ --wait for lineage id--> urn:adsk.wipprod:fs.file:vf.<id>?version=1+```++- The bridge trusts the STEP's origin and orientation as published on the wiki. It does+ **not** rotate or translate by bounding box: some chips are lopsided and no bounding-box+ rule is ever right for all of them (`orient:false`).+- The saved design lives in the user's project under `Adom AI Workspace/<library name>/`,+ one per package. That folder is the 3D package store; Fusion's own GUI keeps the same kind+ of design, it just hides it. Do not delete it: the library's urns point at it.+- The lineage id doubles as the version id for these single-version designs, which is why+ the urn can be constructed rather than looked up.++## What a multi-part library goes through++```+bundle.zip (one merged .lbr, N STEPs)+ -> unpack (zip-slip guarded, size capped), place under Documents/AdomLibraries/<name>/+ -> pair every deviceset with a STEP by name (deviceset, package, normalised, prefix)+ -> SPLIT the merged library into one temporary library per deviceset+ -> mint each part on ITS OWN library (fact 3 above)+ -> bind all N urns into the merged .lbr in one pass (merge-aware, idempotent)+ -> open the merged library, prove every deviceset (4 frames each, measured)+ -> save the library to <project>/Adom Libraries/<name> (Library Manager lists it)+ -> close the scratch (generators, <pkg>_3d tabs, temp libraries), leave the library open+```++### Why the split matters: the wrong-footprint run++The first multi-part run minted all three parts against the merged library. Because the+generator loads the **first** package of whatever library is open, chips two and three were+imported onto part one's footprint, saved, uploaded, bound and "proven". Here is+TPS54427DDAR on XL7026E1's footprint; the pads run out past the left edge of the body:++++After the split, the same chip on its own SOP-8 footprint, a pad under every lead:++++The mint now reads the generator document's name back (Fusion names it after the package it+loaded) and refuses with `wrong_footprint_loaded` if it is not the package being minted, so+this class of error fails before anything is uploaded.++### The finished library++Three devicesets in one library, each with its symbol, footprint and rendering 3D package:++++## What the user sees while it runs++The bridge shows an Adom-branded palette inside Fusion for the whole run, including while+the Package3D generator is active (this is a capture of that palette during the generator+stage):++++The Quick Actions page (and any web-control caller) gets the same run as a 1 fps live view+of the Fusion window with its owned popups composited at their screen positions, the+bridge's measured percent, the stage text, and the proof frames as they land:++++Several wiki parts can be picked into one multi-part library from the page:++++## Proof, not "done"++`fusion_prove_result` is the single poll surface. `stage: done` only means the chain+finished; the score is `verdict`. Every deviceset is proved with four frames (symbol,+footprint, package3d, ganged), each frame is measured from the file (a 237x39 title-bar+sliver once passed as a "symbol" until this check existed), and `provedParts[]` is per part.+`partMetadata` reports missing MPN / manufacturer / distributor numbers; it never blocks the+import, it bubbles up so someone can fix the data upstream.++## Contracts worth knowing++| Situation | What you get |+|---|---|+| A deviceset has no STEP in the bundle | a named skip in `unbound[]`; the rest still bind; `partsBound < partsTotal` |+| No STEP at all | `installed:true`, `nothing_to_bind`, nothing opened in Fusion |+| Fusion closed | the chain launches it (about a minute) and carries on |+| Fusion open, add-in silent | the chain **asks** (toast + `addin_restart_required` in the run) and waits; "Save and restart" continues the same run, "I'll handle it" stops it with `user_owns_restart` |+| The bridge restarts mid-run | `bridge_restarted_mid_run`, honest and terminal; scratch documents are swept before the next run |+| Same library name already in `Adom Libraries` | reported in `cloudLibrary.olderSameName`; retired only with `replaceExisting:true` |++## Skills++- `fusion-multipart-libraries`: the manual recipe (per-part f3d, urn construction, binding+ markup, merge rules) and the dead ends.+- `fusion-web-control`: the import lane, pre-flight, progress, evidence, and every failure+ contract, for web callers and AI threads alike.+- `fusion-part-metadata`: MPN, manufacturer and distributor numbers, and variants.+- `fusion-ralph-test-via-wiki`: how the bridge tests this lane the way a user drives it.
docs/img/multipart/banner-in-package3d-generator.pngadded⋯ 1 unchanged line ⋯
docs/img/multipart/library-three-parts-ganged.pngadded⋯ 1 unchanged line ⋯
docs/img/multipart/own-footprint-tps54427ddar.pngadded⋯ 1 unchanged line ⋯
docs/img/multipart/quick-actions-live-view.pngadded⋯ 1 unchanged line ⋯
docs/img/multipart/quick-actions-multi-pick.pngadded⋯ 1 unchanged line ⋯
docs/img/multipart/wrong-footprint-tps54427ddar.pngadded⋯ 1 unchanged line ⋯
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.263"+DASH_VERSION="1.9.264" 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.263",+ "version": "1.9.264", "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,6 +1,6 @@ { "slug": "fusion-bridge",- "version": "1.9.263",+ "version": "1.9.264", "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": {@@ -11,6 +11,10 @@ "uninstall": "./uninstall.sh" }, "tags": [+ "ab",+ "bridge",+ "fusion",+ "desktop-app", "fusion360", "autodesk", "cad",@@ -75,7 +79,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.",@@ -104,9 +111,5 @@ "label": "Part volume", "prompt": "How much material does each printed part in this assembly use?" }- ],- "author": {- "name": "John Lauer",- "email": "[email protected]"- }-}+ ]+}
server.py+31@@ -4519,6 +4519,14 @@ def _build_library_3d_core(args: dict) -> dict: for p in parts: pkg = p.get("package") per_lbr = (p.get("lbrPath") or "").replace("\\", "/")+ # CLEAN UP PER PART, NOT AT THE END (John, 2026-08-29: "be better about clean up as you+ # progress"). Snapshot the open documents now; everything this part opens (its+ # generator Untitled, its <pkg>_3d design, its temporary library) is closed the moment+ # its urn is in hand, so a 20-part library never has 40 tabs waiting for a final sweep.+ try:+ _docs_before_part = _open_doc_names()+ except Exception:+ _docs_before_part = set() step = (p.get("modelPath") or "").replace("\\", "/") if not pkg or not per_lbr or not step: results.append({"package": pkg, "success": False,@@ -4553,6 +4561,10 @@ def _build_library_3d_core(args: dict) -> dict: if mk.get("after"): shots.append({"package": pkg, "stage": "after", "path": mk["after"]}) results.append(entry)+ try:+ entry["scratchClosed"] = _close_docs_opened_since(_docs_before_part)+ except Exception:+ entry["scratchClosed"] = [] _emit_part(entry, len(results), len(parts)) # inject every binding in ONE pass, write the bound library. Read the ALREADY-BOUND output if it # exists so a re-run ACCUMULATES (merge-aware) onto prior successes instead of starting clean.@@ -12115,6 +12127,17 @@ def _publish_library_to_cloud(lbr_path: str, name: str, folder: str = "Adom Libr # Make the library the active document ourselves (the generic helper also demands a # library workspace and gave up after the prove left a 3D document in front, 2026-08-29). import time as _tpa+ # The prove stage closes the library behind itself, so it is usually NOT open here; open it+ # from disk (the bound file is the truth) before trying to activate it.+ try:+ if stem.lower() not in {n.rstrip("*").strip().lower() for n in _open_doc_names()}:+ _op = _orchestrate_open_lbr({"filePath": lbr_path})+ out["reopened"] = bool(_op.get("success"))+ if not _op.get("success"):+ out["error"] = "could not reopen the library to save it: " + str(_op.get("error"))[:160]+ return out+ except Exception as e:+ out["reopenNote"] = str(e)[:120] _deadline = _tpa.time() + 120 _seen = None _active_ok = False@@ -12556,6 +12579,14 @@ def _handle_create_library(fusion_info: dict, args: dict) -> dict: "error": _r.get("error")}) state["provedParts"] = _prove_results _all_ok = _all_ok and bool(_r.get("proven"))+ # Close what THIS deviceset's frames opened (the 3D frame's design, any+ # Untitled) before moving to the next one; the library itself stays.+ try:+ _lib_stem = (target_lbr or "").replace("\\", "/").rsplit("/", 1)[-1].rsplit(".", 1)[0].lower()+ _prove_results[-1]["scratchClosed"] = _close_docs_opened_since(+ _docs_before, keep={_lib_stem})+ except Exception:+ pass _save() # The library is proven only if EVERY part is. One good part does not vouch # for nine unchecked ones.
skills/fusion-multipart-libraries/SKILL.md+5−1@@ -21,7 +21,11 @@ real chip, flat on its footprint, built entirely this way. > the generator loads the merged file's first package, so three chips landed on one footprint, > John 2026-08-29), trusts the STEP's published origin and orientation (`orient:false`, no > bounding-box guesses), binds every urn into the merged library, proves it, and then saves-> it into the user's cloud project under `Adom Libraries` so Fusion's Library Manager lists it.+> it into the user's cloud project under `Adom Libraries` so Fusion's Library Manager lists it,+> and leaves that library OPEN in front of the user (only the scratch is closed). The mint+> refuses with `wrong_footprint_loaded` if the generator loaded a different package than the+> one being minted. The full technical account, with the wrong-footprint and corrected frames,+> is `docs/MULTIPART_LIBRARY_IMPORT.md` on the fusion-bridge wiki page. For a whole many-part library, you no longer loop `make_3d_package` + hand-write bindings. ONE verb does the entire pipeline - per-part footprint+chip f3d packages, **all** bindings injected in one
tools/release.sh+3−1@@ -301,7 +301,9 @@ PUSH_FILES="server.py fusion_detect.py describe.py timings.py aps.py install_add dashboard/src/main.rs dashboard/Cargo.toml dashboard/Cargo.lock dashboard/ui/index.html \ dockbar.json install.sh" for f in handlers/*.py addin/AdomBridge/*.py addin/AdomBridge/commands/*.py \- addin/AdomBridge/*.manifest skills/*/SKILL.md tools/release.sh CLAUDE.md; do+ addin/AdomBridge/*.manifest skills/*/SKILL.md tools/release.sh CLAUDE.md \+ library_bundle.py README.md docs/*.md docs/img/*.svg docs/img/*.png \+ docs/img/*/*.png dashboard/ui/*.html; do [ -f "$f" ] && PUSH_FILES="$PUSH_FILES $f" done echo " pushing $(echo $PUSH_FILES | wc -w) files"