← Commit history

Publish 1.9.256

John Lauer ·f024da5327 ·1mo ago ·parent 2619302
3 files changed +80−12
.release-page-head+1−1
@@ -1 +1 @@-3eba99ebadcfc0d353c44e7dccc8da0917b4e40f\ No newline at end of file+26193027f45ad94e0c4e9c8cbe65b5cc199413d6\ No newline at end of file
library_bundle.py+72−1
@@ -91,7 +91,8 @@ def pair_parts(lbr_path: str, models: list, metadata: dict) -> dict:      def _take(m, how, ds):         used.add(m)-        parts.append({"package": ds, "lbrPath": lbr_path, "modelPath": m, "matchedBy": how})+        parts.append({"deviceset": ds, "package": packages.get(ds) or ds, "lbrPath": lbr_path,+                      "modelPath": m, "matchedBy": how})      for ds in devicesets:         pk = packages.get(ds) or ""@@ -142,3 +143,73 @@ def place_library(lbr_path: str, models: list, dest_dir: str) -> dict:         new_models[m] = t     return {"lbrPath": new_lbr.replace("\\", "/"),             "models": {k: v.replace("\\", "/") for k, v in new_models.items()}}+++def split_per_part(lbr_path: str, out_dir: str) -> dict:+    """One library per deviceset, so Create3DPackage loads THAT part's footprint.++    Fusion's Package3D generator loads the FIRST package of the open library whatever path the+    command names, so minting three parts against one merged library put every chip on the+    first part's footprint (John saw it, 2026-08-29). Each per-part file keeps the merged file's+    header and layers and carries exactly: the packages that deviceset's devices use (its+    primary package first), the symbols its gates use, and the deviceset itself.+    Returns {deviceset: {"lbrPath", "package", "symbols"}}.+    """+    import copy+    import xml.etree.ElementTree as ET+    os.makedirs(out_dir, exist_ok=True)+    tree = ET.parse(lbr_path)+    root = tree.getroot()+    lib = root.find(".//library")+    if lib is None:+        raise ValueError("no <library> in %s" % lbr_path)+    pk_all = {p.get("name"): p for p in lib.findall("./packages/package")}+    sy_all = {sy.get("name"): sy for sy in lib.findall("./symbols/symbol")}+    out = {}+    for ds in lib.findall("./devicesets/deviceset"):+        name = ds.get("name") or ""+        pkgs = []+        for dev in ds.findall("./devices/device"):+            pk = dev.get("package")+            if pk and pk not in pkgs:+                pkgs.append(pk)+        syms = []+        for g in ds.findall("./gates/gate"):+            sy = g.get("symbol")+            if sy and sy not in syms:+                syms.append(sy)+        new_root = copy.deepcopy(root)+        new_lib = new_root.find(".//library")+        for tag in ("packages", "symbols", "devicesets", "packages3d"):+            el = new_lib.find(tag)+            if el is not None:+                new_lib.remove(el)+        pe = ET.SubElement(new_lib, "packages")+        for pk in pkgs:+            if pk in pk_all:+                pe.append(copy.deepcopy(pk_all[pk]))+        se = ET.SubElement(new_lib, "symbols")+        for sy in syms:+            if sy in sy_all:+                se.append(copy.deepcopy(sy_all[sy]))+        de = ET.SubElement(new_lib, "devicesets")+        ds2 = copy.deepcopy(ds)+        for inst in ds2.iter("package3dinstances"):+            pass+        for dev in ds2.findall("./devices/device"):+            for inst in dev.findall("package3dinstances"):+                dev.remove(inst)+        de.append(ds2)+        # EAGLE order inside <library>: description?, packages, symbols, devicesets+        children = list(new_lib)+        head = [c for c in children if c.tag not in ("packages", "symbols", "devicesets")]+        for c in children:+            new_lib.remove(c)+        for c in head + [pe, se, de]:+            new_lib.append(c)+        safe = re.sub(r"[^A-Za-z0-9._-]+", "_", name) or "part"+        fp = os.path.join(out_dir, safe + ".lbr").replace("\\", "/")+        ET.ElementTree(new_root).write(fp, encoding="utf-8", xml_declaration=True)+        out[name] = {"lbrPath": fp, "package": pkgs[0] if pkgs else "", "symbols": syms,+                     "packages": pkgs}+    return out
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]"+  }+}\ No newline at end of file