@vcad/mcp 0.9.4-main.20 → 0.9.4-main.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,4 +6,4 @@ vcad's MCP server as a self-contained bundle (server + BRep kernel WASM).
6
6
  { "mcpServers": { "vcad": { "command": "npx", "args": ["-y", "@vcad/mcp"] } } }
7
7
  ```
8
8
 
9
- Built from c5938bcd3843b4e600b28e18b5472d41337bd478 at 2026-07-25T14:49:15.914Z. Source: https://github.com/ecto/vcad
9
+ Built from 34f31195abaa154019b219eda75a0e900b7ece93 at 2026-07-25T19:25:56.201Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -40878,6 +40878,24 @@ var init_CHANGELOG = __esm({
40878
40878
  "run_drc"
40879
40879
  ]
40880
40880
  },
40881
+ {
40882
+ id: "2026-07-25-router-pair-connector-vias",
40883
+ version: "0.9.4",
40884
+ date: "2026-07-25",
40885
+ category: "fix",
40886
+ title: "Autoroute no longer routes traces through diff-pair vias",
40887
+ summary: "Differential-pair breakout vias were written onto the board but never registered with the router's clearance oracle, so later nets were routed straight through the barrel.",
40888
+ features: [
40889
+ "pcb",
40890
+ "routing",
40891
+ "drc"
40892
+ ],
40893
+ mcpTools: [
40894
+ "route_nets",
40895
+ "route_diff_pair",
40896
+ "run_drc"
40897
+ ]
40898
+ },
40881
40899
  {
40882
40900
  id: "2026-07-25-router-diff-pair-si",
40883
40901
  version: "0.9.4",
@@ -40899,6 +40917,45 @@ var init_CHANGELOG = __esm({
40899
40917
  "build_receipt"
40900
40918
  ]
40901
40919
  },
40920
+ {
40921
+ id: "2026-07-25-impedance-geometry-per-layer",
40922
+ version: "0.9.4",
40923
+ date: "2026-07-25",
40924
+ category: "feat",
40925
+ title: "Controlled-impedance geometry solved per layer",
40926
+ summary: "A net class can declare a target impedance and vcad derives the trace and diff-pair width per layer from the board stackup \u2014 microstrip on the outers, stripline on the inners \u2014 with the router preferring layers where the geometry is impedance-correct.",
40927
+ features: [
40928
+ "pcb",
40929
+ "autorouter",
40930
+ "diff-pairs",
40931
+ "signal-integrity",
40932
+ "stackup"
40933
+ ],
40934
+ mcpTools: [
40935
+ "route_nets",
40936
+ "set_design_rules",
40937
+ "set_stackup",
40938
+ "calc_impedance",
40939
+ "build_receipt"
40940
+ ]
40941
+ },
40942
+ {
40943
+ id: "2026-07-25-gerber-pad-rotation",
40944
+ version: "0.9.4",
40945
+ date: "2026-07-25",
40946
+ category: "fix",
40947
+ title: "Gerber export honours pad rotation",
40948
+ summary: "Pads on rotated footprints are exported with the correct orientation; previously every non-square pad was flashed axis-aligned, shorting fine-pitch packages.",
40949
+ features: [
40950
+ "pcb",
40951
+ "gerber",
40952
+ "fabrication"
40953
+ ],
40954
+ mcpTools: [
40955
+ "export_gerber",
40956
+ "fab_prep"
40957
+ ]
40958
+ },
40902
40959
  {
40903
40960
  id: "2026-07-24-visionos-app",
40904
40961
  version: "0.9.4",
@@ -60734,16 +60791,61 @@ async function addCoil(args, opts) {
60734
60791
  if ("error" in lr) return fail2(`layers entry: ${lr.error}`);
60735
60792
  }
60736
60793
  const stitchVias = [];
60737
- const perLayerLen = segLength(pts);
60794
+ const dTheta = sign * turns * 2 * Math.PI;
60795
+ const spiralSteps = Math.max(2, Math.ceil(turns * segmentsPerTurn));
60796
+ const drill = pcb.rules.defaultRules.viaDrill;
60797
+ const holePitch = drill + 0.5 + 0.05;
60798
+ const staggerR = Math.max(innerR, traceWidth);
60799
+ const stagger = Math.min(Math.PI / 4, holePitch / (2 * staggerR));
60800
+ const boundary = (li) => li < 0 ? theta0 + dTheta : theta0 - li * dTheta - sign * (li + 1) * stagger;
60801
+ const layerPts = [];
60802
+ for (let li = 0; li < layersIn.length; li++) {
60803
+ const thetaFrom = boundary(li - 1);
60804
+ const thetaTo = boundary(li);
60805
+ const outward = li % 2 === 1;
60806
+ const rFrom = outward ? innerR : outerR;
60807
+ const rTo = outward ? outerR : innerR;
60808
+ const lp = [];
60809
+ for (let s = 0; s <= spiralSteps; s++) {
60810
+ const t2 = s / spiralSteps;
60811
+ const theta = thetaFrom + t2 * (thetaTo - thetaFrom);
60812
+ const r = rFrom + t2 * (rTo - rFrom);
60813
+ const p = {
60814
+ x: round33(center.x + r * Math.cos(theta)),
60815
+ y: round33(center.y + r * Math.sin(theta))
60816
+ };
60817
+ const prev = lp[lp.length - 1];
60818
+ if (!prev || prev.x !== p.x || prev.y !== p.y) lp.push(p);
60819
+ }
60820
+ layerPts.push(lp);
60821
+ }
60822
+ if (innerLeadOut > 0) {
60823
+ for (let li = 0; li + 1 < layersIn.length; li++) {
60824
+ if (li % 2 !== 0) continue;
60825
+ const end = layerPts[li][layerPts[li].length - 1];
60826
+ const thetaEnd = boundary(li);
60827
+ const tx = Math.sin(thetaEnd) * sign;
60828
+ const ty = -Math.cos(thetaEnd) * sign;
60829
+ const T = {
60830
+ x: round33(end.x + tx * innerLeadOut),
60831
+ y: round33(end.y + ty * innerLeadOut)
60832
+ };
60833
+ if (T.x !== end.x || T.y !== end.y) {
60834
+ layerPts[li].push(T);
60835
+ layerPts[li + 1].unshift(T);
60836
+ }
60837
+ }
60838
+ }
60738
60839
  let totalLengthMm = 0;
60739
60840
  let totalTraces = 0;
60740
60841
  let totalResistance = 0;
60741
60842
  for (let li = 0; li < layersIn.length; li++) {
60742
60843
  const lyr = layersIn[li];
60743
- for (let i = 0; i + 1 < pts.length; i++) {
60844
+ const lp = layerPts[li];
60845
+ for (let i = 0; i + 1 < lp.length; i++) {
60744
60846
  pcb.traces.push({
60745
- start: pts[i],
60746
- end: pts[i + 1],
60847
+ start: lp[i],
60848
+ end: lp[i + 1],
60747
60849
  width: traceWidth,
60748
60850
  layer: lyr,
60749
60851
  net,
@@ -60751,12 +60853,12 @@ async function addCoil(args, opts) {
60751
60853
  });
60752
60854
  totalTraces++;
60753
60855
  }
60754
- totalLengthMm += perLayerLen;
60856
+ const layerLen = segLength(lp);
60857
+ totalLengthMm += layerLen;
60755
60858
  const cuT = pcb.stackup.layers.find((s) => s.layer === lyr)?.copperThickness ?? 0.035;
60756
- totalResistance += 168e-7 * perLayerLen / (traceWidth * cuT);
60859
+ totalResistance += 168e-7 * layerLen / (traceWidth * cuT);
60757
60860
  if (li + 1 < layersIn.length) {
60758
- const atInner = li % 2 === 0;
60759
- const stitchPt = atInner ? pts[0] : pts[pts.length - 1];
60861
+ const stitchPt = lp[lp.length - 1];
60760
60862
  pcb.vias.push({
60761
60863
  position: stitchPt,
60762
60864
  diameter: pcb.rules.defaultRules.viaDiameter,
@@ -60769,9 +60871,10 @@ async function addCoil(args, opts) {
60769
60871
  stitchVias.push({ position: stitchPt, startLayer: lyr, endLayer: layersIn[li + 1] });
60770
60872
  }
60771
60873
  }
60772
- const lastFreeInner = (layersIn.length - 1) % 2 === 0;
60773
- const terminalA = pts[pts.length - 1];
60774
- const terminalB = lastFreeInner ? pts[0] : pts[pts.length - 1];
60874
+ const lastLp = layerPts[layerPts.length - 1];
60875
+ const terminalA = layerPts[0][0];
60876
+ const terminalB = lastLp[lastLp.length - 1];
60877
+ const lastFreeInner = layersIn.length % 2 === 1;
60775
60878
  return {
60776
60879
  content: [
60777
60880
  {
@@ -60783,14 +60886,14 @@ async function addCoil(args, opts) {
60783
60886
  direction,
60784
60887
  layers_used: layersIn,
60785
60888
  multilayer: true,
60786
- note: "Multilayer stacked coil: `layer` and inner_via/via_to_layer ignored; layers stitched with alternating inner/outer vias.",
60889
+ note: "Multilayer stacked coil: `layer` and inner_via/via_to_layer ignored. One continuous spiral in angle across the stack \u2014 the radius zigzags inner\u2194outer with a stitch via at each turnaround \u2014 so every layer circulates the same way and their fields add.",
60787
60890
  total_traces: totalTraces,
60788
60891
  total_length_mm: Math.round(totalLengthMm * 100) / 100,
60789
60892
  total_resistance_ohms: Math.round(totalResistance * 1e3) / 1e3,
60790
60893
  stitch_vias: stitchVias,
60791
60894
  terminals: { a: terminalA, b: terminalB },
60792
- inner_endpoint: pts[0],
60793
- outer_endpoint: pts[pts.length - 1],
60895
+ inner_endpoint: lastFreeInner ? terminalB : layerPts[0][layerPts[0].length - 1],
60896
+ outer_endpoint: terminalA,
60794
60897
  ...drcCap ? { drc_delta: await drcCap.finish() } : {},
60795
60898
  ...docResultPayload(ctx)
60796
60899
  })
@@ -78061,8 +78164,8 @@ var init_server3 = __esm({
78061
78164
  init_order_feed();
78062
78165
  init_animate();
78063
78166
  PKG_VERSION = (() => {
78064
- if ("0.9.4-main.20") {
78065
- return "0.9.4-main.20";
78167
+ if ("0.9.4-main.22") {
78168
+ return "0.9.4-main.22";
78066
78169
  }
78067
78170
  try {
78068
78171
  const req = createRequire2(import.meta.url);
@@ -78071,8 +78174,8 @@ var init_server3 = __esm({
78071
78174
  return "0.0.0";
78072
78175
  }
78073
78176
  })();
78074
- BUILD_SHA = "c5938bcd3843b4e600b28e18b5472d41337bd478";
78075
- BUILD_TIME = "2026-07-25T14:49:15.914Z";
78177
+ BUILD_SHA = "34f31195abaa154019b219eda75a0e900b7ece93";
78178
+ BUILD_TIME = "2026-07-25T19:25:56.201Z";
78076
78179
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
78077
78180
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
78078
78181
  INSTANCE_ID = randomUUID6().slice(0, 8);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.9.4-main.20",
3
+ "version": "0.9.4-main.22",
4
4
  "description": "vcad MCP server — parametric CAD + PCB design tools for AI agents (self-contained: bundled server + kernel WASM)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "homepage": "https://vcad.io",
21
21
  "vcadBuild": {
22
- "sha": "c5938bcd3843b4e600b28e18b5472d41337bd478",
23
- "builtAt": "2026-07-25T14:49:15.914Z"
22
+ "sha": "34f31195abaa154019b219eda75a0e900b7ece93",
23
+ "builtAt": "2026-07-25T19:25:56.201Z"
24
24
  }
25
25
  }
Binary file