← Commit history

Bundle MAKING_LIBRARIES + LIBRARY_FINDINGS INTO the fusion-libraries skill folder (local links so installed AIs read them); document the bundling technique in the dev skill + a re-sync step in PUBLISHING

John Lauer ·669d65c423 ·4mo ago ·parent 81d185c
5 files changed +394−8
PUBLISHING.md+8
@@ -111,6 +111,14 @@ adom-wiki pr create <org>/<slug> ...        # PR your changes back to the canoni  ![The wiki Releases tab with the published bridge zip asset](pub-releases.png) +## Step 0.5 - re-sync any skill-bundled READMEs++If a bundled skill ships copies of deep docs in its folder (e.g. `skills/fusion-libraries/` carries+`MAKING_LIBRARIES.md` + `LIBRARY_FINDINGS.md` so the installed AI reads them locally), **re-copy the+repo-root READMEs into the skill folder before building the zip**, rewriting their image refs to absolute+wiki URLs (`https://wiki.adom.inc/<org>/<slug>/files/<img>.png`). Otherwise the bundled copy drifts from+the canonical root copy. (See the `fusion-bridge-dev` skill, "Bundle deep READMEs INTO each skill".)+ ## Pitfall checklist (the short version)  - `.zip` -> `release upload`, never `repo push` (gitignored + silently skipped).
skills/fusion-bridge-dev/SKILL.md+12
@@ -88,3 +88,15 @@ Then `bridge_install {manifestUrl, force:true}`. Server-only change (server.py/d that's it (AD respawns the bridge server). Add-in change (addin/) = ALSO `fusion_stop` -> `install_addin.py` -> hash-verify (Get-FileHash, not findstr) -> `fusion_start`. Community: fork the page, release to your fork, `bridge_install` your manifest to test, then PR back.++## Bundle deep READMEs INTO each skill (so the installed AI actually reads them)++When a skill points at companion docs (a step-by-step guide, a findings log), **copy those READMEs INTO+the skill's own folder** (next to its `SKILL.md`) and link them with **plain local paths**+(`[GUIDE.md](GUIDE.md)`). Do NOT use repo-relative links (`../../GUIDE.md`) - they resolve in the repo but+**break once the skill installs** to `~/.claude/skills/<skill>/` (there is no repo root above it). And do+NOT rely only on wiki URLs - a remote fetch is a step the AI may skip; a file sitting right next to the+skill gets read. In the bundled copies, rewrite image refs to **absolute wiki URLs**+(`https://wiki.adom.inc/<org>/<slug>/files/<img>.png`) so screenshots still resolve. The repo-root copies+stay for the wiki Files tab; **re-sync the bundled copies on every publish** (see PUBLISHING.md). Net: the+installed skill carries the full content locally + always-current.
skills/fusion-libraries/LIBRARY_FINDINGS.mdadded+208
@@ -0,0 +1,208 @@+# Getting component libraries into Fusion - findings log++Hard-won findings from cracking "attach the real 3D chip to a Fusion library package." Captured as we+go so the final MAKING_LIBRARIES.md + fusion-libraries skill are complete and correct. Newest insight+at the bottom of each section.++## 1. Use chip-fetcher's curated LIBRARY, not a raw /tmp download++`chip-fetcher/library/<MPN>/` is curated and carries **variant-specific** files. For Fusion, the right+inputs are the **`.fusion`** variant (generated by Adom's `adom-sfconvert`), paired with the curated+named 3D:++| File | Use |+|---|---|+| `<MPN>.fusion.kicad_sym` | symbol, Fusion-tuned -> feed to adom-lbr |+| `<MPN>.fusion.kicad_mod` | footprint, Fusion-tuned -> feed to adom-lbr |+| `<MPN>-named.step` | the curated 3D (part number etched on top; oriented). Pair this with the footprint |+| `<MPN>.kicad_mod` / `.manufacturer.*` / `.altium.*` | raw / other-EDA variants, NOT for Fusion |++MISTAKE made + fixed: I first built the `.lbr` from a raw `/tmp/adom-chip-fetcher-*/EAGLE/*.lbr` and+the thin 245KB `manufacturer.step`. That gave a footprint/3D size mismatch. Switching to+`.fusion.kicad_mod` + `-named.step` is the fix. (Convention confirmed in `chip-fetcher/src/thumbnails.rs`:+it builds the lbr with `--name <mpn>.fusion` from the `.fusion` files.)++![adom-lbr's viewer: symbol | the curated 4-sided LQFP-64 footprint | the embossed 3D | pin->pad map - inspect this before touching Fusion](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/lib-06-adomlbr-viewer.png)++## 2. adom-lbr is the right tool; pass it the .fusion files++`adom-lbr generate --sym <MPN>.fusion.kicad_sym --fp <MPN>.fusion.kicad_mod -o <MPN>.lbr --name <MPN>`+then `adom-lbr validate <MPN>.lbr`. adom-lbr has no 3D/URN flag (it is symbol+footprint only); the 3D+is attached separately in Fusion (sections 4-6). The VENDOR EAGLE `.lbr` must NOT be fed to+`Create3DPackage` - it fails Fusion's XML parser ("File doesn't contain valid XML data"); an+adom-lbr-generated `.lbr` parses fine.++## 3. Getting the .lbr / .step onto Windows++The pipeline runs in the cloud container; Fusion runs on Windows; there is NO container->Windows push+verb. Serve the files (`python3 -m http.server 8931`) and pull them with `shell_execute` ++`Invoke-WebRequest -OutFile C:\Users\<user>\adom-lib\...`. Build the shell JSON with `json.dumps`+(Windows paths need `\\`).++## 4. Opening the footprint in the 3D viewer (Package3DEnvironment)++- `fusion_open_lbr` the `.lbr` so the **library document is ACTIVE** (required).+- `fusion_execute_text_command {"command":"Electron.Create3DPackage C:/.../<MPN>.lbr"}` opens the+  **`Package3DEnvironment`** workspace showing the footprint (green courtyard + pads + `>NAME`/`>VALUE`).+  ERROR if the library is not active: "Please run the command in library document."+- Command defs in that env: `Package3DCmd`, `Package3DCreateCmd`, `Package3DStop` (Stop = FINISH).++## 5. Placing the real 3D chip via the API (works)++Inside the env, with `fusion_run_modeling_script`:+```python+d = adsk.fusion.Design.cast(app.activeProduct); root = d.rootComponent+im = app.importManager+im.importToTarget(im.createSTEPImportOptions("C:/.../<MPN>-named.step"), root)   # the real body+oc = root.occurrences.item(root.occurrences.count-1)+# auto-orient: rotate the smallest bbox dimension to Z so it lies flat+# (named.step is usually already Z-thin; raw STEP often imports Y-up and needs +90 about X)+```+The chip imports at correct scale and sits on the footprint.++## 6. The library-context commands (the proper in-library path)++Enumerating command defs while the **library** is active surfaced the real in-library commands:+- `Electron::AddCustom3DModel` - opens a design to add a custom 3D model to the selected package.+- `AttachToFootprintCmd` - attaches the modeled body to the footprint (this is what maps it back ++  mints the eagle URN). It is INTERACTIVE (holds the main thread waiting for a footprint-align confirm),+  so it resists pure-API completion; recover with Escape if it wedges.+- also: `Electron::EditCustom3DModel`, `Electron::PackageFromWeb`, `Electron::RemoveCustom3DModel`.++## 7. THE URN SCHEME (the crux)++A library `.lbr` references a 3D package by **`urn:adsk.eagle:package:NNNNN/V`** (managed-library scheme),+NOT the **`urn:adsk.wipprod:...`** scheme that `fusion_aps_upload` / `save_to_cloud` produce. So you+cannot just paste an uploaded-STEP URN into the `.lbr`. The eagle URN is minted only when Fusion's 3D+Package Generator FINISHes mapped to the package. The `.lbr` markup (from the EAGLE spec + Autodesk+forum): `<packages3d><package3d urn="urn:adsk.eagle:package:N/V" type="model">...</package3d></packages3d>`+and the device carries `override_package3d_urn` / a `<package3dinstance package3d_urn="...">`.++## 8. Open item++The one step not yet automated end-to-end: minting + mapping the eagle URN (the FINISH inside the+in-library generator). Current plan: open the footprint env with the chip placed (sections 4-5), let+the human align + FINISH/save once, then export that `.lbr`, read the exact `package3d` markup + eagle+URN, and from there automate the edit-and-reupload for every future chip.++## 9. Integration test (adom-lbr.fusion3d/1 sidecar) - results++Tested the adom-lbr-fixed `.lbr` + `ads.fusion3d.json` sidecar end to end:+- **Footprint writer fix: VERIFIED.** The new `adom-lbr generate` emits a real 4-sided LQFP-64+  (16 left / 16 right / 16 top / 16 bottom `<smd>`, X & Y ±5.74 mm), 64 `<connect>` intact. Opens in+  Fusion as a proper QFP, not a 2-column placeholder. (Format nit: the `<smd>` have **no `rot=`** - fine+  for square pads, but non-square pads on the top/bottom sides would need `rot="R90"`.)+- **URN minting: the assumed scheme is WRONG.** Running the 3D Package Generator+  (`Create3DPackage` -> import model -> `Package3DStop`/FINISH -> Save) mints+  **`urn:adsk.wipprod:dm.lineage:...`** (a regular user cloud design), NOT the+  **`urn:adsk.eagle:package:NNN/V`** the manifest expects. Fusion's generator saves a *custom* 3D model+  as an ordinary cloud file (wipprod), not a managed eagle package.+- **Binding the wipprod URN: FAILS.** Writing `<packages3d><package3d urn="urn:adsk.wipprod:dm.lineage:...">`+  + a device `<package3dinstance package3d_urn="...">` into the `.lbr` and reopening gives+  **"<file>.lbr has errors and cannot be opened. Close the empty design file..."** So a wipprod URN is+  not valid in `package3d`; the `.lbr` genuinely needs an `adsk.eagle:package` URN.+- **THE REMAINING BLOCKER:** how to mint an `adsk.eagle:package` URN for a custom model. The standalone+  generator path does not produce one. The in-library `Electron::AddCustom3DModel` + `AttachToFootprintCmd`+  path (section 6) is the likely minter, but it is interactive. This is the crux to crack next.++## 10. Capturing GUI error dialogs (Fusion) - ALWAYS check owned popups++Fusion error dialogs (e.g. "<file>.lbr has errors and cannot be opened") are **owned popups**: they do+NOT enumerate in `desktop_list_windows` and are invisible to a plain capture of the main window. A+`fusion_*` verb can return `success:true` while an error dialog is actually up.++**`desktop_screenshot_window {hwnd}` (AD v1.8.177+) captures them automatically** and returns them at the+TOP LEVEL: **`ownedPopupCount`** (always present; 0 = none) + **`_screenshots[]`** (each owned popup:+`title`, `kind:"owned_popup"`, `localSafePath`, `rect`, `coordMap`). The CLI auto-pulls each popup PNG.++RULE: after every Fusion open / `execute_text_command` / generator FINISH, grab+`desktop_screenshot_window` on the Fusion main hwnd and **check `ownedPopupCount` / read the+`screenshots[]` array** (each entry: `title`, `localSafePath`, `coordMap`, `shotId`; the CLI auto-pulls+each PNG to `/tmp/ad-shots/`). Do NOT just read `output.data.image` (that is the main window only and+misses owned dialogs). Treat `ownedPopupCount > 0` as "a dialog is up - read each popup before proceeding."+(Field note: `_screenshots`/`_popups_note` are doc-strings; the real array is `screenshots`.)++## 11. SUCCESS - the WORKING 3D-attach flow (supersedes the section 9 "bind fails" path)++The manual `package3d`-XML / pre-minted-URN approach (section 9) was a dead end. The **generator FINISH,+launched from the open library, DOES bind the 3D to the deviceset** - no XML editing, no wipprod URN.+Proven end-to-end on ADS8588SIPM (LQFP-64): the Content Manager tree shows the 3D nested under the+package under the deviceset, the Packages panel's `Package` column flips from `Placeholder` to the part+name, and the 3D preview becomes the real chip. **This is the first time the full Fusion electronics 3D+attach has been automated through the bridge.**++![The real ADS8588SIPM chip imported + auto-oriented onto the matched 4-sided footprint in the Package3D environment](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/lib-10-ads-chip-on-footprint.png)++![Bound: the Content Manager shows the 3D under the package under the deviceset, and the Packages `Package` column reads the part name (not Placeholder) with the real 3D preview](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/lib-09-3d-bound-moneyshot.png)++The repeatable sequence (all via existing verbs):+1. Build the `.lbr` from the chip-fetcher **`.fusion`** variant (`adom-lbr generate`); footprint must be a+   real 4-sided package (the writer fix). Stage `.lbr` + the model STEP to Windows.+2. `fusion_open_lbr` the `.lbr` so the **library is the ACTIVE document**.+3. `fusion_execute_text_command Electron.Create3DPackage <C:/...lbr>` -> opens `Package3DEnvironment`+   showing the footprint.+4. `fusion_run_modeling_script`: `importManager.importToTarget(createSTEPImportOptions(<C:/...step>), root)`,+   then auto-orient (rotate the smallest bbox dim to Z so it lies flat on the footprint).+5. `fusion_run_modeling_script`: `ui.commandDefinitions.itemById("Package3DStop").execute()` (FINISH).+6. A **Save** dialog appears (owned dialog) -> `desktop_ui_click` its+   `QTApplication.QTFrameWindow.standardActions.SaveButton`.+7. Back on the library: the deviceset's package now carries the real 3D. **The right-panel preview LAGS** -+   re-grab the window (or click the package in the Content Manager) to see `Package`=part-name + the real+   3D; the tree is the source of truth, the preview refresh is delayed.++PITFALL corrected: do NOT conclude "it didn't bind" from a stale gray preview right after FINISH - check+the Content Manager tree / the `Package` column, and re-grab after a moment.++## 12. GROUND TRUTH - exactly how Fusion bakes the 3D URN into the .lbr++Exported the bound library to `.flbr` (`fusion_export_source` with a `.flbr` extension), which is a+Fusion document ZIP; the EAGLE library XML lives in `.../electron.BlobParts/ExtFile<uuid>` (24 KB,+`<eagle version="9.7.0">`). It DOES contain the 3D, and here is the exact markup Fusion writes for a+CUSTOM (user-uploaded) 3D model:++```xml+<packages3d>+  <package3d name="ADS8588SIPM" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.<id>?version=1"+             locally_modified="yes" type="model">+    <description>ADS8588SIPM</description>+    <packageinstances><packageinstance name="ADS8588SIPM"/></packageinstances>+  </package3d>+</packages3d>+<!-- and inside the matching <device ...>: -->+<package3dinstances>+  <package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.<id>?version=1"/>+</package3dinstances>+```++THE DELTA (why the section-9 manual bind failed):+- `urn=""` is **EMPTY** for a custom model (the `urn` slot is for MANAGED `urn:adsk.eagle:package:N/V`+  content only). The actual reference goes in **`wip_urn=`**.+- The URN form is the **versioned file URN** `urn:adsk.wipprod:fs.file:vf.<id>?version=1`, NOT the+  `dm.lineage` form. (`fusion_aps_upload`/`save_to_cloud` return a `dm.lineage` lineage URN; the+  `?version=1` file URN is the one to use - get it from `fusion_aps_file_info`/the saved version.)+- Add **`locally_modified="yes"`** and `type="model"`.+- The device's `<package3dinstance package3d_urn="...">` uses the SAME `fs.file:vf...?version=1` form.++So the manifest's `adsk.eagle:package` assumption is only for managed-library parts; for a+self-uploaded model the binding is a `wip_urn` (fs.file:vf) with empty `urn`. With this exact shape,+adom-lbr (or the bridge) CAN write the binding directly given the model's versioned file URN - no+generator UI needed. (The generator FINISH path also works and is what produced this reference.)++## 13. Resolved sidecar contract (answers to adom-lbr v1.1.1)++**Q: what does the sidecar ship for the FINISH path?** Just `model.path` + `package` + `placement`.+That is sufficient - the bridge does Create3DPackage -> import -> orient -> FINISH -> Save. `placement`+stays useful as an orientation hint/override (the bridge's auto-orient is "rotate smallest bbox dim to Z";+a known pin-1 rotation/offset in `placement` lets adom-lbr override it when a part needs it).++**Q: write the minted wip_urn back to the sidecar (status -> bound)?** YES, record it - for idempotency+(re-runs detect "already bound"), provenance (which model version), and to enable the offline `bind-3d`+fast-path later. BUT the **in-Fusion library is the runtime source of truth**; the sidecar record is+bookkeeping that **adom-lbr owns + writes**. The bridge's part is to REPORT the minted URN: after the+Save, `fusion_aps_file_info {query:"<package>"}` returns the saved 3D-package design's tip+**`fs.file:vf.<id>?version=N`** URN - adom-lbr writes that into the sidecar (`urn`, `urn_status:"bound"`).++**Q: dm.lineage vs fs.file in the .lbr?** ONLY the versioned **`fs.file:vf.<id>?version=N`** goes in the+`.lbr` - in both `wip_urn=` and the device `package3d_urn=`. NEVER `dm.lineage` in the `.lbr` (Fusion pins+a specific version, consistent with `locally_modified="yes"`). `dm.lineage` is the stable cross-version ID;+keep it (optionally) only as SIDECAR provenance for re-resolving the latest version, never in the binding.
skills/fusion-libraries/MAKING_LIBRARIES.mdadded+158
@@ -0,0 +1,158 @@+# Making component libraries in Fusion 360 (symbol + footprint + 3D)++How an Adom component library is built and gets into Fusion 360 Electronics as a placeable part,+captured end to end on a real part (Nordic **nRF54L15**). It covers the parts that work today and+the one hard step that is still being automated: attaching the real 3D chip via a Fusion cloud URN.++> Companion skill: `skills/fusion-libraries/SKILL.md`. Verb reference: [VERBS.md](VERBS.md).++## The pipeline++```+chip-fetcher  ->  adom-symbol    -> NAME.kicad_sym ┐+(vendor bundle)   adom-footprint -> NAME.kicad_mod ┼-> adom-lbr generate -> NAME.lbr -> fusion_open_lbr+   incl 3D/NAME.stp + NAME.glb                     ┘   (symbol + package + connects)    (Library editor)+                                                       (2D; 3D = placeholder)+                          then: STEP -> Fusion cloud (URN) -> 3D Package Generator -> real 3D on the package+```++| Tool | Role | Output |+|---|---|---|+| **chip-fetcher** | pulls a multi-CAD vendor bundle for an MPN; the content source | `library/<MPN>/<MPN>.step`, `.glb`, vendor EAGLE/KiCad |+| **adom-symbol** | builds the schematic symbol | `NAME.kicad_sym` (2D, no 3D) |+| **adom-footprint** | builds the PCB footprint | `NAME.kicad_mod` (2D, no 3D) |+| **adom-lbr** | assembles + validates the EAGLE library | `NAME.lbr` (symbol + package + deviceset) |++`adom-lbr generate --sym NAME.kicad_sym --fp NAME.kicad_mod -o NAME.lbr` then+`adom-lbr validate NAME.lbr` -> "valid EAGLE .lbr with complete deviceset".++## Step 1 - open the .lbr in Fusion++The `.lbr` is built in the cloud container; Fusion runs on Windows. There is **no container-to-Windows+push verb**, so stage the file first, then open the Windows path.++```bash+# serve from the container+cd <dir-with-lbr> && python3 -m http.server 8931+# download onto Windows (build the JSON in Python; Windows paths need \\ )+adom-desktop shell_execute '{"command":"powershell -NoProfile -Command \"Invoke-WebRequest -Uri https://<workspace>.adom.cloud/proxy/8931/NAME.lbr -OutFile C:\\Users\\<user>\\adom-lib\\NAME.lbr\""}'+# open it+adom-desktop fusion_open_lbr '{"filePath":"C:/Users/<user>/adom-lib/NAME.lbr","verify":true}'+adom-desktop fusion_get_app_state '{}'   # expect activeWorkspace "Electronics Library", isElectronics true+```++The library loads with symbol + footprint + deviceset. The 3D package is a **placeholder** (the Content+Manager 3D tab is empty). This is correct, and is the gap the rest of this guide closes.++![Library open in the Electronics Library editor; symbol + footprint mapped, 3D still a placeholder](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/lib-01-open.png)++## Step 2 - put the 3D model in the Fusion cloud (get a URN)++Fusion does NOT embed the STEP in the `.lbr`. A package references its 3D model by a Fusion cloud+**file URN** (`urn:adsk.wipprod:fs.file:vf.<id>?version=N`). So the model has to live in the cloud+first. Stage the STEP to Windows (same as step 1), then upload it:++```bash+adom-desktop fusion_aps_browse '{}'                                   # find hub + project+adom-desktop fusion_aps_browse '{"projectId":"<proj>"}'               # find the root folder+adom-desktop fusion_aps_create_folder '{"projectId":"<proj>","parentFolderId":"<root>","name":"Electronics 3D"}'+adom-desktop fusion_aps_upload '{"projectId":"<proj>","folderId":"<folder>","localPath":"C:/Users/<user>/adom-lib/NAME.step","fileName":"NAME-3D.step"}'+# -> { "itemUrn": "urn:adsk.wipprod:dm.lineage:...", "bytes": ... }+```++Verified on nRF54L15: the STEP (1088914 bytes) uploaded into `Standard Components / Electronics 3D`+and returned a real URN. (`Electron.getCloudPathFromUrn` confirms the 3D package references a Fusion+**file** URN, which is what this path produces.)++## Step 3 - the 3D Package Generator (attach the model to the footprint)++Fusion exposes a scriptable entry point:++```bash+adom-desktop fusion_execute_text_command '{"command":"Electron.Create3DPackage C:/Users/<user>/adom-lib/NAME.lbr"}'+```++This opens the **3D PACKAGE Generator**: a Design-workspace authoring document with the footprint+loaded (the green courtyard + `>NAME` / `>VALUE`), and a PACKAGE / SELECT / FINISH ribbon.++![The 3D Package Generator with the nRF54L15 footprint loaded, ready for a model](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/lib-02-generator.png)++The generator is itself an `adsk::fusion::Design` in the **`Package3DEnvironment`** workspace, with+three command definitions: `Package3DCmd`, `Package3DCreateCmd`, `Package3DStop` (Stop = FINISH).+So the insert + finish are drivable through `fusion_run_modeling_script` (full `adsk` API):++```python+# inside the generator, via fusion_run_modeling_script:+d = adsk.fusion.Design.cast(app.activeProduct); root = d.rootComponent+im = app.importManager+im.importToTarget(im.createSTEPImportOptions("C:/.../NAME.step"), root)   # the real 3D body+oc = root.occurrences.item(root.occurrences.count-1)                      # STEP imports Y-up;+mat = oc.transform2.copy()                                                # rotate 90 deg about X+mat.transformBy(_rotX(math.pi/2)); oc.transform2 = mat                    # so it lies flat (thin in Z)+ui.commandDefinitions.itemById("Package3DStop").execute()                 # FINISH -> Save dialog+```++This **works**: the real chip imports at correct scale, orients flat, centered on the footprint, and+FINISH saves a 3D package to the cloud (the Save dialog Name/Location are confirmed via `desktop_ui_click`).++![The ADS8588SIPM chip seated on its matched 4-sided LQFP-64 footprint in the Package3D viewer](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/lib-10-ads-chip-on-footprint.png)++### SOLVED - the 3D binds, end to end++Launched from the **open library**, `Electron.Create3DPackage` -> import the model -> orient ->+`Package3DStop` (FINISH) -> Save **does bind the 3D onto the deviceset**. Proven on ADS8588SIPM+(LQFP-64): the Content Manager tree shows the 3D nested under the package under the deviceset, the+Packages panel's `Package` column flips from `Placeholder` to the part name, and the 3D preview becomes+the real chip. First time the full Fusion electronics 3D attach is automated via the bridge.++![3D bound: Content Manager shows the real chip under the package, Package column = part name](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/lib-09-3d-bound-moneyshot.png)++GOTCHA: the right-panel preview LAGS after FINISH (still shows the gray placeholder for a moment) - the+Content Manager tree / `Package` column is the source of truth; re-grab the window after a beat.++### How Fusion stores it (the ground-truth `.lbr` markup)++Export the bound library (`fusion_export_source` to a `.flbr` ZIP; the EAGLE XML is in+`electron.BlobParts/ExtFile<uuid>`) and you see exactly how the 3D is referenced for a CUSTOM model:++```xml+<packages3d>+  <package3d name="<PKG>" urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.<id>?version=1"+             locally_modified="yes" type="model">+    <packageinstances><packageinstance name="<PKG>"/></packageinstances>+  </package3d>+</packages3d>+<!-- inside the <device>: -->+<package3dinstances><package3dinstance package3d_urn="urn:adsk.wipprod:fs.file:vf.<id>?version=1"/></package3dinstances>+```++Key: `urn=""` is empty (that slot is for managed `urn:adsk.eagle:package` parts only); the real link is+**`wip_urn=`** with the **versioned file URN** `urn:adsk.wipprod:fs.file:vf.<id>?version=1` (NOT the+`dm.lineage` form), plus `locally_modified="yes"`. With this exact shape the binding can be written+directly given the model's versioned file URN. Full detail: [LIBRARY_FINDINGS.md](LIBRARY_FINDINGS.md) §11-12.++## Pitfalls++- **Container path to `fusion_open_lbr`/upload** fails - paths must be Windows-local; stage first.+- **Assuming the 3D is there** - adom-lbr output is 2D; the package is a placeholder until step 3 completes.+- **`Electron.Create3DPackage` with no/blank args** opens a stray "Untitled" (or footprint-named) Design;+  close it with `fusion_close_document '{"save":false}'` if you abandon the generator.+- **Guessing the `package3d` XML** - no on-disk example exists (not even vendor EAGLE downloads carry 3D);+  the markup is generated by Fusion. Reverse-engineer from a real FINISH before writing any.+- **`desktop_screenshot_window` needs `hwnd`** (resolve via `desktop_find_window`) and returns inline base64.++## Every verb used in this sequence++| Verb | What it did here |+|---|---|+| `adom-lbr generate` / `validate` | build + validate `NAME.lbr` |+| `shell_execute` (PowerShell `Invoke-WebRequest`) | stage `.lbr` / `.step` onto Windows |+| `fusion_open_lbr` | open the library in the Electronics Library editor |+| `fusion_get_app_state` | confirm active doc / workspace / isElectronics |+| `desktop_find_window` + `desktop_screenshot_window` | capture the Fusion window |+| `fusion_aps_browse` | find the hub / project / root folder |+| `fusion_aps_create_folder` | make the `Electronics 3D` folder |+| `fusion_aps_upload` | upload the STEP to the cloud, return the URN |+| `fusion_list_text_commands` | discover `Electron.Create3DPackage` / `getCloudPathFromUrn` |+| `fusion_execute_text_command` | run `Electron.Create3DPackage <footprint>` |+| `fusion_close_document` | close the generator / stray designs |
skills/fusion-libraries/SKILL.md+8−8
@@ -5,11 +5,11 @@ description: How an Adom component library (symbol + footprint + 3D chip) is bui  # Fusion libraries - symbol + footprint + 3D into a placeable .lbr -> This skill is the concise, self-sufficient entry point for the workflow. The **exhaustive guides +-> screenshots live on the bridge's wiki page** and are fetchable (WebFetch / `adom-wiki repo show` /-> browser): the **[guide](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/MAKING_LIBRARIES.md)**-> and the **[findings log](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/LIBRARY_FINDINGS.md)**.-> Read those for the full walkthrough, the exact `package3d` markup, and every pitfall.+> This skill is the concise entry point. The **exhaustive guides are bundled right here in this skill+> folder** - read them directly: **[MAKING_LIBRARIES.md](MAKING_LIBRARIES.md)** (the full step-by-step+> guide + screenshots) and **[LIBRARY_FINDINGS.md](LIBRARY_FINDINGS.md)** (the findings log: the exact+> `package3d` markup, the owned-popup error-capture technique, and every pitfall). (Their screenshots load+> from the wiki.)  ## 1. The pipeline (where each tool fits) @@ -39,7 +39,7 @@ chip-fetcher  ->  adom-symbol   -> .kicad_sym  ┐   (OpenCASCADE relief on the top face), driven by `chip-fetcher/scripts/occt-name-on-chip.py`. - **fusion_open_lbr** imports the `.lbr` into Fusion's Electronics Library editor. -See **[LIBRARY_FINDINGS.md](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/LIBRARY_FINDINGS.md)** for the full live findings log.+See **[LIBRARY_FINDINGS.md](LIBRARY_FINDINGS.md)** for the full live findings log.  ## 2. Opening a .lbr in Fusion (verified working) @@ -72,7 +72,7 @@ A fresh `.lbr` shows the package as a **placeholder** 3D (the Content Manager 3D urn:adsk.wipprod:fs.file:vf.<id>?version=<N> ``` -**The verified flow (proven on nRF54L15; full walkthrough + screenshots in [MAKING_LIBRARIES.md](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/MAKING_LIBRARIES.md)):**+**The verified flow (proven on nRF54L15; full walkthrough + screenshots in [MAKING_LIBRARIES.md](MAKING_LIBRARIES.md)):** 1. **Model -> cloud -> URN.** Stage the STEP to Windows, then `fusion_aps_upload {projectId, folderId, localPath:"C:/.../<MPN>.step"}` returns a real cloud URN (`urn:adsk.wipprod:dm.lineage:...`). `Electron.getCloudPathFromUrn` confirms the 3D package references a Fusion **file** URN, which this produces. (`fusion_import_file` is NOT a routed verb; do not rely on it.) 2. **Open the generator.** `fusion_execute_text_command {"command":"Electron.Create3DPackage C:/.../<MPN>.lbr"}` opens the **3D PACKAGE Generator**: a Design-workspace doc with the footprint loaded and a PACKAGE / SELECT / FINISH ribbon. 3. **Insert model + FINISH** -> Fusion writes the `package3d` URN back to the library.@@ -84,7 +84,7 @@ the Fusion **Save** dialog via `desktop_ui_click {automationId:'QTApplication.QT The 3D then binds onto the deviceset (Content Manager tree shows it; the `Package` column flips Placeholder -> part name; the preview LAGS a beat). Fusion writes this exact markup (for a self-uploaded model): `<package3d urn="" wip_urn="urn:adsk.wipprod:fs.file:vf.<id>?version=1" locally_modified="yes" type="model">`-+ a device `<package3dinstance package3d_urn="...fs.file:vf...?version=1"/>`. See [LIBRARY_FINDINGS.md](https://wiki.adom.inc/adom/adom-desktop-fusion-bridge/files/LIBRARY_FINDINGS.md) §11-12.++ a device `<package3dinstance package3d_urn="...fs.file:vf...?version=1"/>`. See [LIBRARY_FINDINGS.md](LIBRARY_FINDINGS.md) §11-12.  Uploading models into the user's Fusion cloud is an outward, persistent action - confirm first, and put uploads in a contained folder (we used `Standard Components / Electronics 3D`).