main
John Lauer AI Flow 0.1.54: 3D models checked for which way is up; missing 3D named; the AI told to look 29bd82b 2h ago

The Fusion lane

AI Flow runs a board that lives in Autodesk Fusion (Fusion Electronics) with the same steps, the same gates and the same ledger as a KiCad board. The binary keeps its offline work in KiCad form (the router, the pour planner, the KiCad DRC gate), and every live step lands in Fusion through the Fusion bridge, one edit at a time, each its own undo step, each read back from a fresh export of the board before the next one goes.

Starting a Fusion run

Export the board's EAGLE source from Fusion (.brd), then start with the document name on the box:

adom-aiflow start --board lanetest.brd --spec spec.json --engine <you> \
  --target <box> --remote-board fusion:<board document name> --prompt-time <UTC of the paste>
  • A .brd is converted to board-0.kicad_pcb in the run (parts, pads, nets, outline, tracks, vias, pours with Fusion's own fill). Fusion's Y axis points up and KiCad's points down, so every point is written as (x, -y); rotations keep their number; a mirrored part (bottom side) lands on B.Cu.
  • --remote-board fusion:<doc> is required for a .brd. From then on every live verb the flow sends (kicad_*) is answered by the Fusion bridge for that document instead (see the table).
  • The Fusion board must be the active document on the box (fusion_show_2d_board).

What each step does in Fusion

step in Fusion needs bridge
route on a Fusion run, plans on a fresh copy of the live board (fusion_board_source), so it routes around copper already in Fusion, not the placement snapshot 1.11.17
place land fusion_move_parts: one MOVE and ROTATE per part, read back to 0.001 mm 1.11.12
land route fusion_route_net: one LINE per segment with straight bends (SET WIRE_BEND 2), VIAs at layer changes; the bridge refuses any copper closer than the board's clearance, with pads as their real rectangles 1.11.16
land vias fusion_place_vias 1.11.12
land pours fusion_apply_pours: one POLYGON per pour (isolate, rank from priority, thermals, orphans), RATSNEST fills them; the reply is Fusion's own fill per pour 1.11.12
measure fusion_pour_state: filled area per layer and per net from Fusion's computed fill 1.11.13
unroute --net N fusion_ripup_nets: RIPUP per net; RIPUP hides the net's pour fills, so the bridge shows and refills them and proves the fill is back 1.11.30
analyze / finish fusion_board_source: the live board as EAGLE XML, saved as board-live.brd (and board-live.kicad_pcb); the field screen and the finish checks judge that board 1.11.17
live validate in finish fusion_routing_drc: Autodesk's own DRC; unconnected is Fusion's airwire count 1.11.12

Every mutating call carries the board id and the revision the flow last read. A board changed behind the flow's back is refused (stale_board), never edited blind.

The whole project, by command

adom-aiflow fusion does the Fusion side of a project the same way every time (--help on each step):

step what it does
fusion library --parts <netlist.json> --footprints <folder> --name <Project> ONE library for the project: each part from its wiki component page, Mouser, DigiKey and LCSC numbers (the page's own, then the distributor lookups, each checked against the exact MPN), the chip outline as symbol for ICs, inductors and big capacitors, standard symbols for passives, the etched or coloured 3D bound. Run again with new parts and they join the same library; parts already bound are kept.
fusion reference --kicad <board.kicad_pcb> --spec <spec.json> A reference design's placement and spec coordinates in the Fusion board's frame: moves.json, fixed.json, spec.json.
fusion schematic --netlist <netlist.json> --spec <spec.json> --fixed <fixed.json> --name <Design> The design started with the fab's rules and the fixed parts (fusion_board_seed), the schematic drawn live in labelled groups (fusion_schematic_plan, fusion_schematic_run), checked pin by pin, saved, and the board written for start.
fusion reset A refine pass: every track, via and pour cleared from the live board; the parts stay.
fusion export Gerbers (the JLCPCB CAM job), pick and place, and the BOM with every distributor number, in <run>/manufacturing/. Ask the human first.

On a Fusion run every step's clip films Fusion's main window, the board fitted to the view first. The library sets part names to 0.8 mm and puts values on tDocu, so the silkscreen stays readable on a small board.

Which way is up: every 3D model is checked

A STEP model carries no "up" axis. Many are authored Y-up; the board and Fusion are Z-up. KiCad hides the difference because each footprint carries its model's transform ((model ... (rotate (xyz -90 0 0)) (offset ...))) and KiCad applies it when it shows the part. A Fusion package is bound to the raw STEP, so that transform must be applied first, or the part lies on its side: on the buck molecule (2026-10-06) the 47 uF can lay on its flank and the 5 x 5 mm inductor stood on edge, both Y-up models with a rotate -90 in their footprints.

fusion library therefore, for every model, before binding:

  1. applies the footprint's own model transform (KiCad's convention: rotate X, then Y, then Z, each by the negated angle; then the offset in mm);
  2. measures the result and compares the two board-plane extents with the footprint's courtyard. If another axis fits decisively better than Z, a model with no footprint transform is turned upright and seated on z = 0; a model whose footprint did give a transform is left alone and named as a part to check;
  3. binds the corrected copy (<run>/fusion/models/<model>-zup.step) and names every part it turned in its reply. Parts bound under older rules are bound again on the next fusion library.

The check is a backstop, not a proof. Look at the board in 3D before calling it done: fusion_show_3d_board, then fusion_take_screenshot (Windows window capture cannot see Fusion's 3D viewport and shows a stale frame), and every part must sit on its pads as its datasheet drawing shows.

A failing analyze prints why: lines with the cause of each field-screen neck and the spec change that fixes it: a via whose copper ring is the narrowest copper (viaPower), or another net's track cutting a patch pour off from its pin (planeUnder).

The board's design rules come from the fab, not from Fusion's defaults

A new Fusion board carries Fusion's default rules: 0.35 mm minimum drill, 1 mm (40 mil) from copper to the board edge, and a pad restring of 25 % of the drill, at least 10 mil. They refuse a fab's 0.3 mm vias, push copper a millimetre off the edge, and turn a 1.2 mm drill's 1.6 mm pad into 1.8 mm. Put the fab's rules in the board before routing (the <designrules> block of the .brd the design starts from: clearances, msDrill, mdCopperDimension, rvPadTop with rlMinPadTop, rlMinViaOuter, mtCopper). The converter and the bridge size every pad and via from these rules the way Fusion does: the ring is the drill times the ratio, held between the minimum and the maximum, and a larger library diameter wins.

Spec coordinates (pour polygons, planeUnder regions, stitch vias) are in the run board's frame. A spec written for a KiCad board elsewhere on the sheet must be moved into it, or every one of them lands off the board without an error.

The fields step on a Fusion board

adom-fields 0.6.0 reads a Fusion .brd directly and uses Fusion's computed pour fill, so solve the board the flow pulled:

adom-aiflow analyze current          # pulls the live board to <run>/board-live.brd
adom-fields analyze --board <run>/board-live.brd --spec spec.json --out <run>/fields
adom-aiflow analyze current          # now judged with the solve; then analyze thermal

The solve is tied to the exact bytes of board-live.brd. Any edit in Fusion after the solve makes it stale and the error names the command to run again.

Refining after an analysis

The loop the analysis is there for: when a net fails (a neck carrying too much current, a part running hot), change the spec and take the old copper up before landing the new.

# spec.json: "wideNets": {"VIN": [0.6, 0.4]}
adom-aiflow unroute --net VIN
adom-aiflow route && adom-aiflow gate && adom-aiflow land route
adom-aiflow measure && adom-aiflow analyze current

land route skips a trace already on the board only when it is on the same net, at the same points and at least as wide as planned, so a widened net is landed again rather than skipped.

The bill of materials

fusion_board_bom reads the part attributes on the live board (MPN, MANUFACTURER, MOUSER_PN, DIGIKEY_PN, LCSC_PN, carried from the library through the schematic) and writes bom.csv, one line per part number, and bom-jlcpcb.csv. It names any part missing a distributor number. sourcing check still wants the sourcing decision (a source column and dated stock), which belongs to the design, not the board.

What is not in Fusion (yet)

  • Keepout zones are not landed; pours are drawn clear of them.
  • Removing copper is by whole net (unroute), not by single segment.
  • Arcs (curved wires) in the source are read as straight segments.

The buck molecule in Fusion (2026-10-05)

The 12 V to 5 V, 1 A buck molecule (TPS54202, 28 x 20 mm, 34 parts) built in Fusion from its library to its Gerbers, on a Windows box:

  • Placement and routing: 24 parts landed live; routing closed with 0 unrouted; the KiCad gate passed with 0 errors; 48 traces and the vias landed live.
  • Pours: Fusion filled 466 mm2 on B.Cu and 410 mm2 on F.Cu.
  • First field solve: SW at 133 A/mm2 at U1's SW pin. A GND track crossed the SW patch, so the patch was cut off from the pin and the full 1 A took a 0.5 mm track.
  • First refine: a planeUnder entry keeps other nets out of the SW patch; SW dropped to 46 A/mm2.
  • Second field solve: VIN at 62 A/mm2. The narrowest copper was the ring around a 0.8 mm via's 0.4 mm hole.
  • Second refine: 1.0 mm power vias (viaPower). The final solve: 0 issues, peak 51 A/mm2, U1 about 9 C over ambient.
  • Finish: finish passed. The Gerbers came from Fusion's JLCPCB CAM job, and the BOM carried every distributor number.

Proof run on a test board (2026-10-05)

A four-resistor board, lanetest, open in Fusion on a Windows box:

  • Placement: place land landed four parts, and the readback was exact.
  • Routing: route closed with 0 unrouted, and the KiCad DRC gate found 0 errors.
  • Landing: land route landed five traces live.
  • Pours: land pours drew a GND pour on the bottom layer, and Fusion filled 565.8 mm² of it.
  • First analysis: adom-fields on the live board found VIN at 97 A/mm² through a 0.25 mm track, against a 60 A/mm² limit.
  • Refine: unroute --net VIN, then re-routing VIN at 0.4 mm, re-gating and re-landing it.
  • Second analysis: the new solve reported 0 issues, and both current and thermal passed.