diff --git a/bun.lock b/bun.lock
index 33738ef60..766698e31 100644
--- a/bun.lock
+++ b/bun.lock
@@ -38,7 +38,7 @@
"circuit-json-to-bom-csv": "^0.0.7",
"circuit-json-to-connectivity-map": "^0.0.25",
"circuit-json-to-fdm-component-box": "^0.0.2",
- "circuit-json-to-footprinter": "^0.0.15",
+ "circuit-json-to-footprinter": "^0.0.46",
"circuit-json-to-gerber": "^0.0.94",
"circuit-json-to-kicad": "0.0.157",
"circuit-json-to-pnp-csv": "^0.0.9",
@@ -573,7 +573,7 @@
"circuit-json-to-fdm-component-box": ["circuit-json-to-fdm-component-box@0.0.2", "", { "dependencies": { "@tscircuit/alphabet": "^0.0.25", "circuit-json": "^0.0.465", "fflate": "^0.8.3", "manifold-3d": "3.5.1", "poppygl": "^0.0.26" }, "peerDependencies": { "typescript": "^5" }, "bin": { "circuit-json-to-fdm-component-box": "dist/cli.js" } }, "sha512-9Xv/Q87ZIc+u11zYzVhhSBWCZRzTpp5yitJgVb0kot/zvzMYAvGqrCU9rI9WEsKD2tjK3jOgfy2cXdkcuYoMrQ=="],
- "circuit-json-to-footprinter": ["circuit-json-to-footprinter@0.0.15", "", { "dependencies": { "@tscircuit/footprinter": "^0.0.385", "@tscircuit/math-utils": "^0.0.36", "circuit-json": "^0.0.448", "format-si-unit": "^0.0.10" } }, "sha512-TBRI7rryKSWA15aX0LpNdy4RvKUQQ+qpp3FHpMblPW1IpzKQTQOi6lqcbABWzDllh7Cd3QZEvwYJYjdbGfm5Sw=="],
+ "circuit-json-to-footprinter": ["circuit-json-to-footprinter@0.0.46", "", { "dependencies": { "@tscircuit/footprinter": "0.0.418", "@tscircuit/manifold-2d": "^0.0.6", "@tscircuit/math-utils": "^0.0.36", "circuit-json": "^0.0.453", "format-si-unit": "^0.0.10" } }, "sha512-tvnKI7iX2ysyUEl9CDcG7A74aQSfRuGrNlZUvqt3eJ8qFm6t+QEa1qE14//3k0v3KOSCrG037PWG8Q+mYG37CQ=="],
"circuit-json-to-gerber": ["circuit-json-to-gerber@0.0.94", "", { "dependencies": { "@tscircuit/alphabet": "^0.0.25", "fast-json-stable-stringify": "^2.1.0", "polygon-clipping": "^0.15.7", "transformation-matrix": "^3.0.0" }, "peerDependencies": { "circuit-json": "*", "tscircuit": "*", "typescript": "^5.0.0" }, "bin": { "circuit-to-gerber": "dist/cli.js" } }, "sha512-moJ8C7vFzm20H1Ydzyqyqe3GQQWyyFOmi8qHarmEfzBEeu2exV98nIUIOtI6gSpdP0lMWdYTJKMfkb6xIri1JA=="],
@@ -1319,9 +1319,7 @@
"circuit-json-to-fdm-component-box/poppygl": ["poppygl@0.0.26", "", { "dependencies": { "fast-png": "^8.0.0", "gl-matrix": "^3.4.4", "pureimage": "^0.4.18", "readable-stream": "^4.7.0" }, "peerDependencies": { "typescript": "^5" } }, "sha512-5jnQuKpDCfFT0b9aCm/AidGdzwjw/I3obFpc10j66FY7ZtDPMRekHYU76BzfKDyV5iU8BBWQzxX+8lS9+EEkbg=="],
- "circuit-json-to-footprinter/@tscircuit/footprinter": ["@tscircuit/footprinter@0.0.385", "", { "dependencies": { "@tscircuit/mm": "^0.0.8", "zod": "^3.23.8" }, "peerDependencies": { "circuit-json": "*" } }, "sha512-kJZT+2NqEkgjCnMZCdeib++OAvImjPbXjvylqvGXcdfBXXN1o+GBHCCFszjIThmJngHERdiyEzvDEBAlyCS4bg=="],
-
- "circuit-json-to-footprinter/circuit-json": ["circuit-json@0.0.448", "", {}, "sha512-4qKp+2/aNoynSckOBRg6UcxkySX9XNi9FeXZG8PbTZexPKHUW4HOnuab7UA4SW0YLnppUtCCgx461YEA8ruFqw=="],
+ "circuit-json-to-footprinter/circuit-json": ["circuit-json@0.0.453", "", { "peerDependencies": { "format-si-unit": "*" } }, "sha512-BxdRuD6WPlUXfwQjwZzX0dA9V6CsmusH5SK4UT34oheCU/XPGi+SZuUHfUTqvKd+V8LcCa68+Hjkdld7x4BG1Q=="],
"circuit-json-to-gerber/transformation-matrix": ["transformation-matrix@3.1.0", "", {}, "sha512-oYubRWTi2tYFHAL2J8DLvPIqIYcYZ0fSOi2vmSy042Ho4jBW2ce6VP7QfD44t65WQz6bw5w1Pk22J7lcUpaTKA=="],
diff --git a/lib/shared/circuit-json-to-footprinter.ts b/lib/shared/circuit-json-to-footprinter.ts
index 20c9212e8..e204c4bfc 100644
--- a/lib/shared/circuit-json-to-footprinter.ts
+++ b/lib/shared/circuit-json-to-footprinter.ts
@@ -1,8 +1,8 @@
import type { AnyCircuitElement } from "circuit-json"
import {
- circuitJsonToFootprinter as circuitJsonToFootprinterWithBundledTypes,
type CircuitJsonToFootprinterOptions,
type FootprinterDiscoveryResult,
+ circuitJsonToFootprinter as circuitJsonToFootprinterWithBundledTypes,
} from "circuit-json-to-footprinter"
export type { FootprinterDiscoveryCandidate } from "circuit-json-to-footprinter"
@@ -12,7 +12,7 @@ type CircuitJsonToFootprinter = (
options?: CircuitJsonToFootprinterOptions,
) => FootprinterDiscoveryResult
-// circuit-json-to-footprinter@0.0.15 bundles an older circuit-json type.
-// Keep that compatibility detail isolated at this dependency boundary.
+// circuit-json-to-footprinter bundles its own circuit-json version, which can
+// differ from the CLI peer version. Keep that type drift isolated here.
export const circuitJsonToFootprinter =
circuitJsonToFootprinterWithBundledTypes as CircuitJsonToFootprinter
diff --git a/package.json b/package.json
index e76e0d46f..df82b4c8a 100644
--- a/package.json
+++ b/package.json
@@ -40,7 +40,7 @@
"circuit-json-to-bom-csv": "^0.0.7",
"circuit-json-to-connectivity-map": "^0.0.25",
"circuit-json-to-fdm-component-box": "^0.0.2",
- "circuit-json-to-footprinter": "^0.0.15",
+ "circuit-json-to-footprinter": "^0.0.46",
"circuit-json-to-gerber": "^0.0.94",
"circuit-json-to-kicad": "0.0.157",
"circuit-json-to-pnp-csv": "^0.0.9",
diff --git a/scripts/bun-build.ts b/scripts/bun-build.ts
index a4aad997d..4ac75bfee 100644
--- a/scripts/bun-build.ts
+++ b/scripts/bun-build.ts
@@ -35,10 +35,18 @@ if (!success) {
process.exit(1)
}
+const manifoldWasmSourcePath = Bun.resolveSync(
+ "@tscircuit/manifold-2d/manifold.wasm",
+ import.meta.dir,
+)
+const manifoldWasm = Bun.file(manifoldWasmSourcePath)
+await Bun.write("./dist/cli/manifold.wasm", manifoldWasm)
+
for (const output of outputs) {
console.log(
`${basename(output.path)} ${(output.size / 1024 / 1024).toFixed(2)} MB`,
)
}
+console.log(`manifold.wasm ${(manifoldWasm.size / 1024 / 1024).toFixed(2)} MB`)
export {}
diff --git a/tests/lib/import/__snapshots__/C2871569-thermal-vias.snap.svg b/tests/lib/import/__snapshots__/C2871569-thermal-vias.snap.svg
new file mode 100644
index 000000000..60cece620
--- /dev/null
+++ b/tests/lib/import/__snapshots__/C2871569-thermal-vias.snap.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/tests/lib/import/convert-imported-footprint-to-footprinter.test.ts b/tests/lib/import/convert-imported-footprint-to-footprinter.test.ts
index 24df3cf20..9e33a0f48 100644
--- a/tests/lib/import/convert-imported-footprint-to-footprinter.test.ts
+++ b/tests/lib/import/convert-imported-footprint-to-footprinter.test.ts
@@ -1,4 +1,7 @@
+import "bun-match-svg"
import { expect, test } from "bun:test"
+import { rm, symlink, writeFile } from "node:fs/promises"
+import path from "node:path"
import { fp } from "@tscircuit/footprinter"
import type {
AnyCircuitElement,
@@ -6,8 +9,7 @@ import type {
PcbSmtPad,
SourcePort,
} from "circuit-json"
-import { rm, symlink, writeFile } from "node:fs/promises"
-import path from "node:path"
+import { convertCircuitJsonToPcbSvg } from "circuit-to-svg"
import { convertImportedFootprintToFootprinter } from "lib/import/footprinter/convert-imported-footprint-to-footprinter"
import { generateCircuitJson } from "lib/shared/generate-circuit-json"
import { temporaryDirectory } from "tempy"
@@ -93,6 +95,41 @@ export const TestChip = () => (
}
})
+test("compacts C2871569 while preserving its 4x4 thermal-via array", () => {
+ const circuitJson = fp
+ .string(
+ "qfn64_thermalpad6.3mmx6.3mm_thermalvias4x4_thermalviapitch1mm_thermalviaid0.3048mm_thermalviaod0.6096mm_pillpads_h9.67mm_pw0.28mm_pl0.66mm",
+ )
+ .circuitJson() as AnyCircuitElement[]
+ const exactTsx =
+ "} />"
+
+ const result = convertImportedFootprintToFootprinter({
+ circuitJson,
+ sourceHints: ["C2871569", "QFN-64"],
+ tsx: exactTsx,
+ })
+
+ expect(result.mode).toBe("footprinter")
+ expect(result.candidate?.footprinterString).toContain("_thermalvias4x4")
+ expect(result.candidate?.footprinterString).toContain("_thermalviapitch1mm")
+ expect(result.candidate?.footprinterString).toContain("_thermalviaid0.3048mm")
+ expect(result.candidate?.footprinterString).toContain("_thermalviaod0.6096mm")
+ expect(result.candidate?.holeIntersectionOverUnion).toBeGreaterThan(0.99)
+ expect(result.tsx).not.toContain("footprint={")
+
+ const recoveredCircuitJson = fp
+ .string(result.candidate!.footprinterString)
+ .circuitJson()
+ expect(
+ recoveredCircuitJson.filter((element) => element.type === "pcb_via"),
+ ).toHaveLength(16)
+ expect(convertCircuitJsonToPcbSvg(recoveredCircuitJson)).toMatchSvgSnapshot(
+ import.meta.path,
+ "C2871569-thermal-vias",
+ )
+})
+
test("keeps the exact footprint when copper IoU is at or below 98%", () => {
const circuitJson = fp
.string("res_p1.3mm_pw0.55mm_ph0.7mm")
@@ -101,7 +138,7 @@ test("keeps the exact footprint when copper IoU is at or below 98%", () => {
if (!firstPad || firstPad.type !== "pcb_smtpad") {
throw new Error("Expected an SMT pad")
}
- firstPad.shape = "circle"
+ Object.assign(firstPad, { radius: 0.1, shape: "circle" as const })
const exactTsx = "} />"
const result = convertImportedFootprintToFootprinter({