diff --git a/docs/CIRCUIT_JSON_PCB_OVERVIEW.md b/docs/CIRCUIT_JSON_PCB_OVERVIEW.md
index f21406d..e48afc2 100644
--- a/docs/CIRCUIT_JSON_PCB_OVERVIEW.md
+++ b/docs/CIRCUIT_JSON_PCB_OVERVIEW.md
@@ -134,7 +134,24 @@ export interface PcbPlatedHoleOval {
pcb_plated_hole_id: string
}
-export type PcbPlatedHole = PcbPlatedHoleCircle | PcbPlatedHoleOval
+export interface PcbHoleCircularWithRectPad {
+ type: "pcb_plated_hole"
+ shape: "circular_hole_with_rect_pad"
+ hole_shape: "circle"
+ pad_shape: "rect"
+ hole_diameter: number
+ rect_pad_width: number
+ rect_pad_height: number
+ x: Distance
+ y: Distance
+ layers: LayerRef[]
+ port_hints?: string[]
+ pcb_component_id?: string
+ pcb_port_id?: string
+ pcb_plated_hole_id: string
+}
+
+export type PcbPlatedHole = PcbPlatedHoleCircle | PcbPlatedHoleOval | PcbHoleCircularWithRectPad
export interface PcbFabricationNoteText {
type: "pcb_fabrication_note_text"
diff --git a/tests/gerber/__snapshots__/paste-layer-bottom.snap.svg b/tests/gerber/__snapshots__/paste-layer-bottom.snap.svg
new file mode 100644
index 0000000..190999b
--- /dev/null
+++ b/tests/gerber/__snapshots__/paste-layer-bottom.snap.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/tests/gerber/__snapshots__/paste-layer-top.snap.svg b/tests/gerber/__snapshots__/paste-layer-top.snap.svg
new file mode 100644
index 0000000..8587f51
--- /dev/null
+++ b/tests/gerber/__snapshots__/paste-layer-top.snap.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/tests/gerber/generate-gerber-with-paste.test.tsx b/tests/gerber/generate-gerber-with-paste.test.tsx
new file mode 100644
index 0000000..04ce69e
--- /dev/null
+++ b/tests/gerber/generate-gerber-with-paste.test.tsx
@@ -0,0 +1,83 @@
+import { test, expect } from "bun:test"
+import { convertSoupToGerberCommands } from "src/gerber/convert-soup-to-gerber-commands"
+import {
+ convertSoupToExcellonDrillCommands,
+ stringifyExcellonDrill,
+} from "src/excellon-drill"
+import { stringifyGerberCommandLayers } from "src/gerber/stringify-gerber"
+import { maybeOutputGerber } from "tests/fixtures/maybe-output-gerber"
+import { Circuit } from "@tscircuit/core"
+
+test("Generate gerber with paste layers", async () => {
+ const circuit = new Circuit()
+ circuit.add(
+
+ {/* Top layer pads */}
+
+
+
+ {/* Bottom layer pads */}
+
+
+ ,
+ )
+
+ const circuitJson = circuit.getCircuitJson()
+
+ // Generate commands
+ const gerber_cmds = convertSoupToGerberCommands(circuitJson)
+ const excellon_drill_cmds_plated = convertSoupToExcellonDrillCommands({
+ circuitJson: circuitJson,
+ is_plated: true, // Paste usually goes with plated holes
+ })
+ const excellon_drill_cmds_unplated = convertSoupToExcellonDrillCommands({
+ circuitJson: circuitJson,
+ is_plated: false,
+ })
+
+ // Stringify outputs
+ const gerberOutput = stringifyGerberCommandLayers(gerber_cmds)
+ const excellonDrillOutputPlated = stringifyExcellonDrill(
+ excellon_drill_cmds_plated,
+ )
+ const excellonDrillOutputUnplated = stringifyExcellonDrill(
+ excellon_drill_cmds_unplated,
+ )
+
+ // Optionally write files for debugging
+ await maybeOutputGerber(gerberOutput, excellonDrillOutputPlated)
+
+ // Assert against snapshot
+ // This will generate SVGs for each layer, including F_Paste and B_Paste
+ expect({
+ ...gerberOutput,
+ "drill_plated.drl": excellonDrillOutputPlated,
+ "drill_unplated.drl": excellonDrillOutputUnplated,
+ }).toMatchGerberSnapshot(import.meta.path, "paste-layer")
+})