← Commit history

Forum videos sub-readme: three true-flow videos, what each answers, how they were made, and the draft reply

John Lauer ·74cad40837 ·1d ago ·parent f2571c0
6 files changed +377
README.md+1
@@ -41,6 +41,7 @@ Short version below, full detail in each guide. | [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, the `needs_signin` short-circuit, `restartPolicy`, 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. |+| [Videos for the Autodesk forum reply](docs/forum-videos.md) | Why we made three true-flow videos (prompt typed in Hydrogen, Fusion doing the work), which of a forum poster's five Electron.run problems each one answers, how they were recorded and cut with no dead air, and the draft reply. | | [Driving Fusion's preferences](docs/fusion-preferences.md) | Reach ANY Fusion preference, not just the thin API slice, by driving the Preferences dialog. | | [Contributing](CONTRIBUTING.md) | Check out the source, change it, test it on your own box, and send a pull request for review. Account and CLI setup, the dialog rules, unsigned local builds, the verb suite, and how review and approval work. | 
docs/forum-videos.mdadded+180
@@ -0,0 +1,180 @@+# Videos for the Autodesk forum reply++This page explains three short videos we made to answer a question on Autodesk's Fusion+Electronics forum, what each one shows, and the reply we drafted around them. Nothing here+is posted yet: the reply goes out from John's Autodesk account once he approves it.++## Why these videos exist++On 2026-10-02, Aske Carstensen posted+[Electronics API + MCP: modal dialogs block scripts, no undo for Electron.run edits](https://forums.autodesk.com/t5/fusion-electronics-forum/electronics-api-mcp-modal-dialogs-block-scripts-no-undo-for/td-p/14286758)+in Autodesk's Fusion Electronics forum. He edits schematics from Claude Desktop through+Autodesk's Fusion MCP. The Electronics API is read-only, so every edit goes through+`executeTextCommand('Electron.run ...')`, and he listed five things that make that fragile.+He ended with a question: "is there a recommended way to drive Electron.run safely until+then?" Autodesk replied that a write API is coming "in the very near term" and marked the+thread solved.++We have spent five months on exactly this problem in the open-source Fusion bridge, so we+can answer his question today. The forum's rules put promotion in Classifieds, so the reply+has to stand on its own as help: concrete answers to his five points, with a video wherever+showing is clearer than telling.++Each video is a real run. You see the exact prompt typed into an AI (Codex, in Hydrogen),+then Fusion doing the work, with the AI's own progress in a corner of the frame. Nothing is+staged; the only edits are cuts and speed-ups of the waiting, timed to the narration so+there is no dead air.++## His five points, and what the bridge does today++| # | Aske's problem | What the bridge does | Shown in |+|---|---|---|---|+| 1 | A modal dialog from an `Electron.run` error blocks every later script | Reads every open Fusion dialog through Windows UI Automation (title, text, buttons), answers known ones, cancels unknown ones in the background, and returns the text to the agent | Video 1 |+| 2 | `ADD` opens the library browser and Fusion waits for a person | The same path cancels it. Better still, parts are written as EAGLE source and opened with `Document.newDesignFromLocal`, so `ADD` is never needed | Video 1 |+| 3 | No undo for `Electron.run` edits | Not solved natively. The bridge saves checkpoints before each batch | |+| 4 | A hidden "armed" command state refuses writes | `ui.terminateActiveCommand()` after each script, the same workaround he found | |+| 5 | MCP screenshots fail in the schematic and PCB editors | The bridge captures the Fusion window itself, which works in both editors, even with Fusion in the background | Video 2 (every frame) |+| ? | "A recommended way to drive Electron.run safely until then?" | An AI writes a schematic, a 2D board and a 3D board from one prompt today | Video 2 |++## Video 1: a modal dialog blocks a script, and the AI clears it++Answers his points 1 and 2.++<iframe width="100%" height="380" src="https://www.youtube.com/embed/FzQjRKxkYLA" title="Modal dialog" frameborder="0" allowfullscreen></iframe>++**The prompt typed into Hydrogen:**++> In Fusion, open the ToF showcase board you made. Then show me how the bridge handles a+> modal dialog that blocks a script: run the ADD command from a script so the library picker+> opens and blocks it, then read that dialog and cancel it in the background.++What you see: the script runs `ADD`, Fusion's library picker pops up over your work and the+script hangs, exactly as Aske describes. The bridge reads the dialog's title and buttons and+cancels it in the background without taking focus, and the script carries on.++## Video 2: from a parts library to a 3D board, from one prompt++Answers his closing question, and his point 5: every frame of Fusion here is a capture of the+schematic and PCB editors themselves.++<iframe width="100%" height="380" src="https://www.youtube.com/embed/HF2bDMRoGfw" title="Library to 3D board" frameborder="0" allowfullscreen></iframe>++**The prompt typed into Hydrogen:**++> In Fusion, make a schematic and a board with every part in my Adom_ToF library. Then show+> me the schematic, the 2D board and the 3D board, and orbit the 3D view so I can see the parts.++What you see: Codex reads the bridge's commands, finds the three sensors in the library,+writes the schematic and the board, opens them with no dialogs, and walks through the+schematic, the 2D board and the 3D board with each part's real 3D model. About eight minutes,+hands off.++## Video 3: a real 3D model on every part of a library++Not on Aske's list, but the next wall anyone writing designs from code hits, and the part+that took us longest.++<iframe width="100%" height="380" src="https://www.youtube.com/embed/vUnqaDy8-XU" title="3D library" frameborder="0" allowfullscreen></iframe>++**The prompt typed into Hydrogen:**++> Build a Fusion library from my Demo Board cloud library on the Adom wiki, with the real 3D+> model bound to every part, and save it to my Fusion Library Manager.++Three traps make this hard:++1. **A STEP in the cloud is not enough.** Bind a raw STEP's urn and the library says+   "Thumbnail download failed". Only a Fusion design (`.f3d`) with the STEP inside renders.+2. **The GUI path is a dialog trap.** The 3D package generator ends with FINISH, which opens+   a Save dialog and two browser modals that no script can read or close.+3. **The generator loads the first package of the open library,** whatever you ask for, so+   in a multi-part library every chip lands on part one's footprint.++The order that works: split the library into one library per part; start the generator on+that part's library so it loads that footprint; import the STEP exactly as the maker+published it; Save As an `.f3d` instead of FINISH; wait for the cloud lineage id and build+the urn from it; write every urn into the merged library in one pass, and open it once. The+full account, with screenshots of the wrong-footprint trap, is in+[Multi-part library import](MULTIPART_LIBRARY_IMPORT.md).++## How the videos were made++- **The run.** A Windows box with Hydrogen and Fusion side by side. The prompt is typed into+  Codex in Hydrogen; Codex drives Fusion through this bridge, with no human input after the+  prompt.+- **The capture.** Adom Bridge records the Hydrogen and Fusion windows in the background+  (Windows Graphics Capture), so nothing has to be in front. Video 1 records the whole+  monitor, because Fusion's picker is its own window and pops up over Hydrogen.+- **The edit.** `tools/video/compose.py` takes a list of sections (a time range of the+  recording, a layout and one narration line each), voices each line with adom-tts, and+  speeds up or slows each section so it lasts exactly as long as its line. That is what keeps+  the narration continuous with no dead air.+- **The hosting.** Unlisted on the Adom Industries YouTube channel, embedded in the forum+  reply with the forum's own video button.++## The draft forum reply++Not posted. John reviews it and posts it from his own Autodesk account.++> Hi Aske, disclosure: I run Adom. We make a free, MIT-licensed Fusion add-in and local+> bridge that lets an AI drive Fusion Electronics end to end, and over the last five months+> we have hit your whole list.+>+> Jorge's news is good: when Autodesk's electronics write API lands, we will build on it, and+> on Autodesk's MCP servers, because native support makes all of this simpler. But to your+> closing question, yes, you can drive Electron.run safely today. Here is how, point by point:+>+> 1. **Modal dialogs.** Before each command we read every open Fusion dialog through Windows+>    UI Automation (title, text, buttons), answer the ones we recognise, cancel unknown ones+>    in the background, and hand the text back to the agent instead of hanging. One warning:+>    Fusion's floating Browser panel is also titled "Fusion360", and closing it can close+>    Fusion, so only close windows that are plainly dialogs.+> 2. **The library browser from ADD.** The same path cancels it, and the video below is+>    exactly your case: a script runs ADD, the picker blocks it, the AI reads the dialog and+>    cancels it, and the script carries on. Better still, we never need ADD: we write parts+>    as EAGLE source and open it with Document.newDesignFromLocal, which raises no dialog.+>+>    *[Video 1]*+>+> 3. **Undo.** Nothing native for Electron.run edits yet, so we save checkpoints before each+>    batch.+> 4. **The armed state.** Your terminateActiveCommand workaround matches ours.+> 5. **Screenshots of the 2D editors.** We capture the Fusion window itself, which works on+>    schematics and boards, even with Fusion in the background. Every Fusion frame in the next+>    video was captured that way.+>+> Putting it together, this is one prompt to an AI writing electronics end to end: it opens a+> parts library, writes a schematic, places the parts on a 2D board and checks the 3D board,+> with no dialogs.+>+> *[Video 2]*+>+> One more wall you will hit once you write designs, not on your list: parts need 3D models,+> and attaching STEP models to a multi-part library is where we spent the most time. Three+> traps: a raw STEP bound by urn shows "Thumbnail download failed" (only an .f3d renders);+> the 3D package generator's FINISH opens modals no script can close; and the generator loads+> the first package of the open library, so every chip lands on part one's footprint. What+> works, in this order: one library per part, start the generator on it, import the STEP,+> Save As an .f3d instead of FINISH, build the urn from the cloud lineage id, then write+> every urn into the merged library in one pass. Six parts bind in about three and a half+> minutes.+>+> *[Video 3]*+>+> The source is public, with a contributing guide if you want to send fixes back:+> [wiki.adom.inc/adom/fusion-bridge](https://wiki.adom.inc/adom/fusion-bridge). Happy to+> compare notes, and thanks Jorge for passing these to the API team.++## Other threads worth a short reply++From a scan of the Fusion Electronics and API forums, 2026-09-10 to 2026-10-04. Drafts only.++- [Report: 100 million tokens... a dialog box: my week making Fusion's MCP work for ECAD](https://forums.autodesk.com/t5/fusion-electronics-forum/report-100-million-tokens-one-rfc-deep-dive-and-a-dialog-box-my/td-p/14275047):+  the same dialog wall. A reply with the UI Automation approach and the EAGLE-source route,+  with a disclosure line.+- [When will we get file write in API?](https://forums.autodesk.com/t5/fusion-electronics-forum/when-will-we-get-file-write-in-api/td-p/14279375):+  the EAGLE-source plus `Document.newDesignFromLocal` workaround that works today. No link.+- [Request access to public-mcp-api for Autodesk Fusion Data MCP](https://forums.autodesk.com/t5/fusion-api-and-scripts-forum/request-access-to-public-mcp-api-for-autodesk-fusion-data-mcp/td-p/14279381):+  Autodesk's 9/29 client allow-list fix, and APS search as the fast path today. No link.++The first and third threads are the same person, so post those a day apart.
tools/video/compose.pyadded+44
@@ -0,0 +1,44 @@+# compose.py spec.json out.mp4 : true-flow video. Each section = a source range [a,b] (recording seconds),+# a mode ("hyd" = Hydrogen chat full frame, "fus" = Fusion full frame with the live chat inset), a short+# label and one narration line. Each section's picture is retimed to fit its line, so there is no dead air.+import json, subprocess, sys, os+spec, out = json.load(open(sys.argv[1])), sys.argv[2]+F, H, CROP = spec["fusion"], spec["hydrogen"], spec.get("chatCrop", "1192:1250:88:268")+ICROP = spec.get("insetCrop", "1192:760:88:758")+LEAD, GAP, MINF = 0.1, 0.3, 0.5+FONT = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"+def dur(p): return float(subprocess.run(["ffprobe","-v","error","-show_entries","format=duration","-of","csv=p=0",p],capture_output=True,text=True).stdout)+def esc(t): return t.replace("\\","\\\\").replace(":", "\\:").replace("'", "’")+stem = os.path.splitext(os.path.basename(out))[0]; os.makedirs("cmp", exist_ok=True)+parts, t, rep = [], 0.0, []+for i, s in enumerate(spec["sections"]):+    a, b = s.get("a",0), s.get("b",1); mp3 = f"cmp/{stem}-{i}.mp3"; raw = mp3.replace(".mp3", "-raw.mp3")+    subprocess.run(["adom-tts","say","--out",raw,"--rate","+4%",s["text"]], check=True, capture_output=True)+    subprocess.run(["ffmpeg","-nostdin","-v","error","-y","-i",raw,"-af","silenceremove=start_periods=1:start_threshold=-45dB,areverse,silenceremove=start_periods=1:start_threshold=-45dB,areverse","-c:a","libmp3lame","-q:a","2",mp3], check=True)+    d = dur(mp3); f = max((b - a) / (LEAD + d + GAP), MINF)+    lab = f",drawtext=fontfile={FONT}:text='{esc(s['label'])}':x=28:y=26:fontsize=30:fontcolor=white:box=1:[email protected]:boxborderw=12"+    if s["mode"] == "img":+        seg = f"cmp/{stem}-v{i}.mp4"; L = LEAD + d + GAP+        subprocess.run(["nice","-n","19","ffmpeg","-nostdin","-v","error","-y","-threads","2","-loop","1","-t",f"{L:.3f}","-i",s["img"],+            "-vf","scale=1920:1080,fps=30,format=yuv420p","-c:v","libx264","-x264-params","threads=2","-crf","20","-preset","fast","-g","30","-keyint_min","30",seg], check=True)+        sd = dur(seg); parts.append((seg, mp3, t + LEAD)); rep.append(f"{i}: card {s['img']} -> {t:5.1f}-{t+sd:5.1f}"); t += sd; continue+    if s["mode"] == "full":+        fc = f"[0:v]crop={spec.get('fullCrop','iw:ih:0:0')},scale=-2:1080,pad=1920:1080:(ow-iw)/2:0:color=0x0d1117,setpts=(PTS-STARTPTS)/{f},fps=30{lab}[v]"+    elif s["mode"] == "hyd":+        fc = f"[1:v]crop={CROP},scale=-2:1080,pad=1920:1080:(ow-iw)/2:0:color=0x0d1117,setpts=(PTS-STARTPTS)/{f},fps=30{lab}[v]"+    else:+        fc = (f"[0:v]scale=1920:-2,pad=1920:1080:0:(oh-ih)/2:color=0x0d1117,setpts=(PTS-STARTPTS)/{f}[bg];"+              f"[1:v]crop={ICROP},scale=760:-2,pad=iw+6:ih+6:3:3:color=0x00b8b1,setpts=(PTS-STARTPTS)/{f}[ins];"+              f"[bg][ins]overlay=W-w-24:H-h-24:shortest=1,fps=30{lab}[v]")+    seg = f"cmp/{stem}-v{i}.mp4"+    subprocess.run(["nice","-n","19","ffmpeg","-nostdin","-v","error","-y","-threads","2",+        "-ss",str(a),"-t",str(b-a),"-i",F,"-ss",str(a),"-t",str(b-a),"-i",H,"-filter_complex",fc,"-map","[v]","-an",+        "-c:v","libx264","-x264-params","threads=2","-crf","21","-preset","fast","-g","30","-keyint_min","30","-pix_fmt","yuv420p",seg], check=True)+    sd = dur(seg); parts.append((seg, mp3, t + LEAD)); rep.append(f"{i}: {a:6.1f}-{b:6.1f} {s['mode']} x{f:5.2f} -> {t:5.1f}-{t+sd:5.1f} line {d:4.1f}s"); t += sd+open(f"cmp/{stem}.txt","w").write("".join(f"file '{os.path.basename(p)}'\n" for p,_,_ in parts))+subprocess.run(["ffmpeg","-nostdin","-v","error","-y","-f","concat","-safe","0","-i",f"cmp/{stem}.txt","-c","copy",f"cmp/{stem}-video.mp4"], check=True)+ins, flt = [], []+for k,(_,mp3,at) in enumerate(parts): ins += ["-i", mp3]; flt.append(f"[{k+1}:a]adelay={int(at*1000)}:all=1[a{k}]")+fc = ";".join(flt)+";"+"".join(f"[a{k}]" for k in range(len(parts)))+f"amix=inputs={len(parts)}:normalize=0,apad[aout]"+subprocess.run(["nice","-n","19","ffmpeg","-nostdin","-v","error","-y","-i",f"cmp/{stem}-video.mp4",*ins,"-filter_complex",fc,"-map","0:v","-map","[aout]","-c:v","copy","-c:a","aac","-b:a","160k","-shortest","-movflags","+faststart",out], check=True)+print("\n".join(rep)); print(f"total {dur(out):.1f}s")
tools/video/spec-3d.jsonadded+94
@@ -0,0 +1,94 @@+{+ "fusion": "uf/window-2428056-20261004-205223.mp4",+ "hydrogen": "uf/window-3409738-20261004-205223.mp4",+ "sections": [+  {+   "a": 2.5,+   "b": 11,+   "mode": "hyd",+   "label": "The prompt, typed into Codex in Hydrogen",+   "text": "The prompt, typed into Codex in Hydrogen: build a Fusion library from my Demo Board cloud library on the Adom wiki, with the real 3D model bound to every part."+  },+  {+   "a": 11,+   "b": 80,+   "mode": "fus",+   "label": "Codex finds the parts and their STEP models",+   "text": "Codex finds the six parts in that cloud library, each with a real STEP model, and hands them to the Fusion bridge."+  },+  {+   "mode": "img",+   "img": "cards/02-why.png",+   "label": "",+   "text": "This is the hard part. A STEP file in the cloud won't render; only a Fusion design does. The generator's FINISH button opens dialogs no script can close. And it always loads the first package in the library."+  },+  {+   "mode": "img",+   "img": "cards/03-wrong-right.png",+   "label": "",+   "text": "That third trap puts a chip on another part's footprint, on the left. The fix puts it on its own, on the right."+  },+  {+   "mode": "img",+   "img": "cards/04-order.png",+   "label": "",+   "text": "So the order matters: one library per part, load that footprint, import the STEP, save it as a Fusion design, then write every cloud link into the library in one pass."+  },+  {+   "a": 80,+   "b": 128,+   "mode": "fus",+   "label": "Part 1 of 6: LAN7800",+   "text": "Part one, the LAN7800. The generator loads its own footprint, the chip goes on top exactly as the maker published it, and it's saved to the cloud as a Fusion design."+  },+  {+   "a": 128,+   "b": 165,+   "mode": "fus",+   "label": "Part 2 of 6: CH340G",+   "text": "Part two, the CH340G USB serial chip, on its own split library, so it lands on its own footprint."+  },+  {+   "a": 165,+   "b": 215,+   "mode": "fus",+   "label": "Part 3 of 6: STM32L431",+   "text": "Part three, the STM32 microcontroller, in its 64 pin package."+  },+  {+   "a": 215,+   "b": 255,+   "mode": "fus",+   "label": "Part 4 of 6: 16 MHz crystal",+   "text": "Part four, a 16 megahertz crystal, on its four pad footprint."+  },+  {+   "a": 255,+   "b": 295,+   "mode": "fus",+   "label": "Part 5 of 6: LED",+   "text": "Part five, a tiny LED, its body sitting right on its pads."+  },+  {+   "a": 295,+   "b": 345,+   "mode": "fus",+   "label": "Part 6 of 6: 10 uF capacitor",+   "text": "And part six, a ten microfarad capacitor."+  },+  {+   "a": 345,+   "b": 640,+   "mode": "fus",+   "label": "One library, every 3D link written in one pass, saved",+   "text": "Then every cloud link goes into one library in a single pass, and Codex checks every binding and saves the library to Fusion's Library Manager."+  },+  {+   "a": 640,+   "b": 656,+   "mode": "hyd",+   "label": "Codex reports back",+   "text": "Codex reports back: six parts, every one with its real 3D model, saved to the Library Manager, in about ten minutes."+  }+ ]+}\ No newline at end of file
tools/video/spec-board.jsonadded+9
@@ -0,0 +1,9 @@+{"fusion":"uf/window-2428056-20261004-201709.mp4","hydrogen":"uf/window-3409738-20261004-201709.mp4","sections":[+ {"a":8.5,"b":17,"mode":"hyd","label":"The prompt, typed into Codex in Hydrogen","text":"This is the whole prompt, typed into Codex in Hydrogen: make a schematic and a board with every part in my ToF library, then show me each view."},+ {"a":17,"b":160,"mode":"fus","label":"Codex plans the build through the Fusion bridge","text":"Codex reads the Fusion bridge's commands, finds the three sensors in the library, and plans the build."},+ {"a":160,"b":232,"mode":"fus","label":"Schematic and board generated, opened with no dialogs","text":"It writes the schematic and the board, and opens them in Fusion without a single dialog."},+ {"a":232,"b":268,"mode":"fus","label":"The 2D board it wrote","text":"Here's the board it wrote: all three sensors placed and labeled, with the library's name on the silkscreen."},+ {"a":312,"b":352,"mode":"fus","label":"The schematic","text":"Here's the schematic, each sensor drawn with its full pinout, straight from the library."},+ {"a":355,"b":392,"mode":"fus","label":"The 2D board layout","text":"And the 2D board layout, the same three parts sitting on their real footprints."},+ {"a":395,"b":478,"mode":"fus","label":"3D board with each part's real 3D model","text":"Then the 3D board. Every part shows its real 3D model, because the bridge bound one to each footprint when it built the library. Codex orbits the camera so you can see them."},+ {"a":478,"b":492,"mode":"hyd","label":"Codex reports back","text":"Codex reports back: all three parts in the schematic, the 2D board and the 3D board, in about eight minutes, hands off."}]}
tools/video/spec-modal.jsonadded+49
@@ -0,0 +1,49 @@+{+ "fusion": "uf/desktop-m0-20261004-212039.mp4",+ "hydrogen": "uf/desktop-m0-20261004-212039.mp4",+ "sections": [+  {+   "a": 2,+   "b": 11,+   "mode": "full",+   "label": "The prompt, typed into Codex in Hydrogen",+   "text": "This prompt asks Codex to recreate Aske's point two: run the ADD command from a script, so Fusion's library picker blocks it."+  },+  {+   "a": 11,+   "b": 98,+   "mode": "full",+   "label": "Codex opens the board and runs ADD from a script",+   "text": "Codex opens the board in Fusion, then runs ADD from a script."+  },+  {+   "a": 98,+   "b": 150,+   "mode": "full",+   "label": "Fusion's modal picker pops up, and the script is blocked",+   "text": "And there it is: Fusion's modal library picker pops up over your work, and the script is stuck until someone closes it."+  },+  {+   "a": 150,+   "b": 203,+   "mode": "full",+   "label": "The bridge reads the dialog through UI Automation",+   "text": "The bridge reads the dialog through Windows UI Automation: its title, its text, and all four buttons."+  },+  {+   "a": 203,+   "b": 216,+   "mode": "full",+   "label": "Cancelled in the background, no focus stolen",+   "text": "Then it presses Cancel in the background, with no mouse and no focus change, and the script carries on."+  },+  {+   "a": 230,+   "b": 250,+   "mode": "full",+   "label": "Codex reports back",+   "text": "Codex reports back: the script resumed, and Fusion is responsive again, with no blocking dialogs."+  }+ ],+ "fullCrop": "1720:1530:0:0"+}\ No newline at end of file