@tscircuit/core 0.0.1273 → 0.0.1275

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +180 -31
  2. package/dist/index.js +245 -56
  3. package/package.json +3 -2
package/dist/index.d.ts CHANGED
@@ -236,9 +236,9 @@ interface IIsolatedCircuit {
236
236
  interface IRootCircuit extends IIsolatedCircuit {
237
237
  }
238
238
 
239
- declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "RenderIsolatedSubcircuits", "InflateSubcircuitCircuitJson", "SourceNameDuplicateComponentRemoval", "PcbFootprintStringRender", "FetchPartFootprint", "InitializePortsFromChildren", "CreateNetsFromProps", "AssignFallbackProps", "CreateTracesFromProps", "CreateTracesFromNetLabels", "CreateTraceHintsFromProps", "CreateAutoplacedBreakoutPoints", "SourceGroupRender", "AssignNameToUnnamedComponents", "SourceRender", "SourceComponentPropertyValidation", "SourceParentAttachment", "PortMatching", "OptimizeSelectorCache", "SourceTraceRender", "SourceAddConnectivityMapKey", "SourceDesignRuleChecks", "SimulationRender", "SchematicComponentRender", "SchematicPortRender", "SymbolContainerRender", "SchematicPrimitiveRender", "SchematicSymbolResize", "SchematicComponentSizeCalculation", "SchematicLayout", "SchematicSectionRender", "SchematicTraceRender", "SchematicReplaceNetLabelsWithSymbols", "PanelBoardLayout", "ValidatePcbCoordinates", "PcbComponentRender", "PcbPrimitiveRender", "PcbFootprintLayout", "PcbPortRender", "PcbPortAttachment", "PcbComponentSizeCalculation", "PcbComponentAnchorAlignment", "PcbCalcPlacementResolution", "PcbLayout", "PcbBoardAutoSize", "PanelLayout", "PcbTraceHintRender", "PcbManualTraceRender", "PcbTraceRender", "PcbRouteNetIslands", "PcbCopperPourRender", "PcbDesignRuleChecks", "SilkscreenOverlapAdjustment", "CadModelRender", "PartsEngineRender", "SupplierFootprintMismatchWarning", "SimulationSpiceEngineRender"];
239
+ declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "RenderIsolatedSubcircuits", "InflateSubcircuitCircuitJson", "SourceNameDuplicateComponentRemoval", "PcbFootprintStringRender", "FetchPartFootprint", "InitializePortsFromChildren", "CreateNetsFromProps", "AssignFallbackProps", "CreateTracesFromProps", "CreateTracesFromNetLabels", "CreateTraceHintsFromProps", "CreateAutoplacedBreakoutPoints", "SourceGroupRender", "AssignNameToUnnamedComponents", "SourceRender", "SourceComponentPropertyValidation", "SourceParentAttachment", "PortMatching", "OptimizeSelectorCache", "SourceTraceRender", "SourceAddConnectivityMapKey", "SourceDesignRuleChecks", "SimulationRender", "SchematicComponentRender", "SchematicPortRender", "SymbolContainerRender", "SchematicPrimitiveRender", "SchematicSymbolResize", "SchematicComponentSizeCalculation", "SchematicLayout", "SchematicSectionRender", "SchematicTraceRender", "SchematicReplaceNetLabelsWithSymbols", "PanelBoardLayout", "ValidatePcbCoordinates", "PcbComponentRender", "PcbPrimitiveRender", "PcbFootprintLayout", "PcbPortRender", "PcbPortAttachment", "PcbComponentSizeCalculation", "PcbComponentAnchorAlignment", "PcbCalcPlacementResolution", "PcbLayout", "PcbBoardAutoSize", "PanelLayout", "PcbAutoplaceBreakoutPoints", "PcbTraceHintRender", "PcbManualTraceRender", "PcbTraceRender", "PcbRouteNetIslands", "PcbCopperPourRender", "PcbDesignRuleChecks", "SilkscreenOverlapAdjustment", "CadModelRender", "PartsEngineRender", "SupplierFootprintMismatchWarning", "SimulationSpiceEngineRender"];
240
240
  type RenderPhase = (typeof orderedRenderPhases)[number];
241
- declare const renderPhaseIndexMap: Map<"ReactSubtreesRender" | "RenderIsolatedSubcircuits" | "InflateSubcircuitCircuitJson" | "SourceNameDuplicateComponentRemoval" | "PcbFootprintStringRender" | "FetchPartFootprint" | "InitializePortsFromChildren" | "CreateNetsFromProps" | "AssignFallbackProps" | "CreateTracesFromProps" | "CreateTracesFromNetLabels" | "CreateTraceHintsFromProps" | "CreateAutoplacedBreakoutPoints" | "SourceGroupRender" | "AssignNameToUnnamedComponents" | "SourceRender" | "SourceComponentPropertyValidation" | "SourceParentAttachment" | "PortMatching" | "OptimizeSelectorCache" | "SourceTraceRender" | "SourceAddConnectivityMapKey" | "SourceDesignRuleChecks" | "SimulationRender" | "SchematicComponentRender" | "SchematicPortRender" | "SymbolContainerRender" | "SchematicPrimitiveRender" | "SchematicSymbolResize" | "SchematicComponentSizeCalculation" | "SchematicLayout" | "SchematicSectionRender" | "SchematicTraceRender" | "SchematicReplaceNetLabelsWithSymbols" | "PanelBoardLayout" | "ValidatePcbCoordinates" | "PcbComponentRender" | "PcbPrimitiveRender" | "PcbFootprintLayout" | "PcbPortRender" | "PcbPortAttachment" | "PcbComponentSizeCalculation" | "PcbComponentAnchorAlignment" | "PcbCalcPlacementResolution" | "PcbLayout" | "PcbBoardAutoSize" | "PanelLayout" | "PcbTraceHintRender" | "PcbManualTraceRender" | "PcbTraceRender" | "PcbRouteNetIslands" | "PcbCopperPourRender" | "PcbDesignRuleChecks" | "SilkscreenOverlapAdjustment" | "CadModelRender" | "PartsEngineRender" | "SupplierFootprintMismatchWarning" | "SimulationSpiceEngineRender", number>;
241
+ declare const renderPhaseIndexMap: Map<"ReactSubtreesRender" | "RenderIsolatedSubcircuits" | "InflateSubcircuitCircuitJson" | "SourceNameDuplicateComponentRemoval" | "PcbFootprintStringRender" | "FetchPartFootprint" | "InitializePortsFromChildren" | "CreateNetsFromProps" | "AssignFallbackProps" | "CreateTracesFromProps" | "CreateTracesFromNetLabels" | "CreateTraceHintsFromProps" | "CreateAutoplacedBreakoutPoints" | "SourceGroupRender" | "AssignNameToUnnamedComponents" | "SourceRender" | "SourceComponentPropertyValidation" | "SourceParentAttachment" | "PortMatching" | "OptimizeSelectorCache" | "SourceTraceRender" | "SourceAddConnectivityMapKey" | "SourceDesignRuleChecks" | "SimulationRender" | "SchematicComponentRender" | "SchematicPortRender" | "SymbolContainerRender" | "SchematicPrimitiveRender" | "SchematicSymbolResize" | "SchematicComponentSizeCalculation" | "SchematicLayout" | "SchematicSectionRender" | "SchematicTraceRender" | "SchematicReplaceNetLabelsWithSymbols" | "PanelBoardLayout" | "ValidatePcbCoordinates" | "PcbComponentRender" | "PcbPrimitiveRender" | "PcbFootprintLayout" | "PcbPortRender" | "PcbPortAttachment" | "PcbComponentSizeCalculation" | "PcbComponentAnchorAlignment" | "PcbCalcPlacementResolution" | "PcbLayout" | "PcbBoardAutoSize" | "PanelLayout" | "PcbAutoplaceBreakoutPoints" | "PcbTraceHintRender" | "PcbManualTraceRender" | "PcbTraceRender" | "PcbRouteNetIslands" | "PcbCopperPourRender" | "PcbDesignRuleChecks" | "SilkscreenOverlapAdjustment" | "CadModelRender" | "PartsEngineRender" | "SupplierFootprintMismatchWarning" | "SimulationSpiceEngineRender", number>;
242
242
  type RenderPhaseFn<K extends RenderPhase = RenderPhase> = `doInitial${K}` | `update${K}` | `remove${K}`;
243
243
  type RenderPhaseStates = Record<RenderPhase, {
244
244
  initialized: boolean;
@@ -73055,14 +73055,191 @@ declare class Footprint extends PrimitiveComponent<typeof footprintProps> {
73055
73055
 
73056
73056
  declare class Breakout extends Group<typeof breakoutProps> {
73057
73057
  constructor(props: z.input<typeof breakoutProps>);
73058
+ /**
73059
+ * Find ports inside this breakout group that are connected to traces
73060
+ * crossing the breakout boundary, and create auto-placed BreakoutPoint
73061
+ * children for them. Positions are not set here — they will be determined
73062
+ * after PcbLayout.
73063
+ */
73064
+ doInitialCreateAutoplacedBreakoutPoints(): void;
73065
+ doInitialPcbAutoplaceBreakoutPoints(): void;
73058
73066
  doInitialPcbPrimitiveRender(): void;
73059
73067
  }
73060
73068
 
73061
- declare class BreakoutPoint extends PrimitiveComponent<typeof breakoutPointProps> {
73069
+ /**
73070
+ * Shared base props for breakout points — layout props without rotation/layer.
73071
+ * Subclasses extend this schema with additional fields (e.g. `connection`).
73072
+ */
73073
+ declare const baseBreakoutPointProps: zod.ZodObject<Omit<{
73074
+ pcbX: zod.ZodOptional<zod.ZodUnion<[zod.ZodString, zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>]>>;
73075
+ pcbY: zod.ZodOptional<zod.ZodUnion<[zod.ZodString, zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>]>>;
73076
+ pcbLeftEdgeX: zod.ZodOptional<zod.ZodUnion<[zod.ZodString, zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>]>>;
73077
+ pcbRightEdgeX: zod.ZodOptional<zod.ZodUnion<[zod.ZodString, zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>]>>;
73078
+ pcbTopEdgeY: zod.ZodOptional<zod.ZodUnion<[zod.ZodString, zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>]>>;
73079
+ pcbBottomEdgeY: zod.ZodOptional<zod.ZodUnion<[zod.ZodString, zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>]>>;
73080
+ pcbOffsetX: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73081
+ pcbOffsetY: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73082
+ pcbRotation: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73083
+ pcbPositionAnchor: zod.ZodOptional<zod.ZodString>;
73084
+ pcbPositionMode: zod.ZodOptional<zod.ZodEnum<["relative_to_group_anchor", "auto", "relative_to_board_anchor", "relative_to_component_anchor"]>>;
73085
+ shouldBeOnEdgeOfBoard: zod.ZodOptional<zod.ZodBoolean>;
73086
+ layer: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodEnum<["top", "bottom", "inner1", "inner2", "inner3", "inner4", "inner5", "inner6"]>, zod.ZodObject<{
73087
+ name: zod.ZodEnum<["top", "bottom", "inner1", "inner2", "inner3", "inner4", "inner5", "inner6"]>;
73088
+ }, "strip", zod.ZodTypeAny, {
73089
+ name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
73090
+ }, {
73091
+ name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
73092
+ }>]>, "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6", "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6" | {
73093
+ name: "top" | "bottom" | "inner1" | "inner2" | "inner3" | "inner4" | "inner5" | "inner6";
73094
+ }>>;
73095
+ pcbMarginTop: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73096
+ pcbMarginRight: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73097
+ pcbMarginBottom: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73098
+ pcbMarginLeft: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73099
+ pcbMarginX: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73100
+ pcbMarginY: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73101
+ pcbStyle: zod.ZodOptional<zod.ZodObject<{
73102
+ silkscreenFontSize: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73103
+ viaPadDiameter: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73104
+ viaHoleDiameter: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
73105
+ silkscreenTextPosition: zod.ZodOptional<zod.ZodUnion<[zod.ZodEnum<["centered", "outside", "none"]>, zod.ZodObject<{
73106
+ offsetX: zod.ZodNumber;
73107
+ offsetY: zod.ZodNumber;
73108
+ }, "strip", zod.ZodTypeAny, {
73109
+ offsetX: number;
73110
+ offsetY: number;
73111
+ }, {
73112
+ offsetX: number;
73113
+ offsetY: number;
73114
+ }>]>>;
73115
+ silkscreenTextVisibility: zod.ZodOptional<zod.ZodEnum<["hidden", "visible", "inherit"]>>;
73116
+ }, "strip", zod.ZodTypeAny, {
73117
+ silkscreenFontSize?: number | undefined;
73118
+ viaPadDiameter?: number | undefined;
73119
+ viaHoleDiameter?: number | undefined;
73120
+ silkscreenTextPosition?: "centered" | "outside" | "none" | {
73121
+ offsetX: number;
73122
+ offsetY: number;
73123
+ } | undefined;
73124
+ silkscreenTextVisibility?: "hidden" | "visible" | "inherit" | undefined;
73125
+ }, {
73126
+ silkscreenFontSize?: string | number | undefined;
73127
+ viaPadDiameter?: string | number | undefined;
73128
+ viaHoleDiameter?: string | number | undefined;
73129
+ silkscreenTextPosition?: "centered" | "outside" | "none" | {
73130
+ offsetX: number;
73131
+ offsetY: number;
73132
+ } | undefined;
73133
+ silkscreenTextVisibility?: "hidden" | "visible" | "inherit" | undefined;
73134
+ }>>;
73135
+ pcbSx: zod.ZodOptional<ZodType<_tscircuit_props.PcbSx, zod.ZodTypeDef, _tscircuit_props.PcbSx>>;
73136
+ pcbRelative: zod.ZodOptional<zod.ZodBoolean>;
73137
+ relative: zod.ZodOptional<zod.ZodBoolean>;
73138
+ }, "layer" | "pcbRotation">, "strip", zod.ZodTypeAny, {
73139
+ pcbX?: string | number | undefined;
73140
+ pcbY?: string | number | undefined;
73141
+ pcbLeftEdgeX?: string | number | undefined;
73142
+ pcbRightEdgeX?: string | number | undefined;
73143
+ pcbTopEdgeY?: string | number | undefined;
73144
+ pcbBottomEdgeY?: string | number | undefined;
73145
+ relative?: boolean | undefined;
73146
+ pcbOffsetX?: number | undefined;
73147
+ pcbOffsetY?: number | undefined;
73148
+ pcbPositionAnchor?: string | undefined;
73149
+ pcbPositionMode?: "auto" | "relative_to_group_anchor" | "relative_to_board_anchor" | "relative_to_component_anchor" | undefined;
73150
+ shouldBeOnEdgeOfBoard?: boolean | undefined;
73151
+ pcbMarginTop?: number | undefined;
73152
+ pcbMarginRight?: number | undefined;
73153
+ pcbMarginBottom?: number | undefined;
73154
+ pcbMarginLeft?: number | undefined;
73155
+ pcbMarginX?: number | undefined;
73156
+ pcbMarginY?: number | undefined;
73157
+ pcbStyle?: {
73158
+ silkscreenFontSize?: number | undefined;
73159
+ viaPadDiameter?: number | undefined;
73160
+ viaHoleDiameter?: number | undefined;
73161
+ silkscreenTextPosition?: "centered" | "outside" | "none" | {
73162
+ offsetX: number;
73163
+ offsetY: number;
73164
+ } | undefined;
73165
+ silkscreenTextVisibility?: "hidden" | "visible" | "inherit" | undefined;
73166
+ } | undefined;
73167
+ pcbSx?: _tscircuit_props.PcbSx | undefined;
73168
+ pcbRelative?: boolean | undefined;
73169
+ }, {
73170
+ pcbX?: string | number | undefined;
73171
+ pcbY?: string | number | undefined;
73172
+ pcbLeftEdgeX?: string | number | undefined;
73173
+ pcbRightEdgeX?: string | number | undefined;
73174
+ pcbTopEdgeY?: string | number | undefined;
73175
+ pcbBottomEdgeY?: string | number | undefined;
73176
+ relative?: boolean | undefined;
73177
+ pcbOffsetX?: string | number | undefined;
73178
+ pcbOffsetY?: string | number | undefined;
73179
+ pcbPositionAnchor?: string | undefined;
73180
+ pcbPositionMode?: "auto" | "relative_to_group_anchor" | "relative_to_board_anchor" | "relative_to_component_anchor" | undefined;
73181
+ shouldBeOnEdgeOfBoard?: boolean | undefined;
73182
+ pcbMarginTop?: string | number | undefined;
73183
+ pcbMarginRight?: string | number | undefined;
73184
+ pcbMarginBottom?: string | number | undefined;
73185
+ pcbMarginLeft?: string | number | undefined;
73186
+ pcbMarginX?: string | number | undefined;
73187
+ pcbMarginY?: string | number | undefined;
73188
+ pcbStyle?: {
73189
+ silkscreenFontSize?: string | number | undefined;
73190
+ viaPadDiameter?: string | number | undefined;
73191
+ viaHoleDiameter?: string | number | undefined;
73192
+ silkscreenTextPosition?: "centered" | "outside" | "none" | {
73193
+ offsetX: number;
73194
+ offsetY: number;
73195
+ } | undefined;
73196
+ silkscreenTextVisibility?: "hidden" | "visible" | "inherit" | undefined;
73197
+ } | undefined;
73198
+ pcbSx?: _tscircuit_props.PcbSx | undefined;
73199
+ pcbRelative?: boolean | undefined;
73200
+ }>;
73201
+ /**
73202
+ * Base class for both user-facing `BreakoutPoint` (which requires a
73203
+ * `connection` prop) and the internal `AutoplacedBreakoutPoint` (which
73204
+ * receives its `matchedPort` programmatically).
73205
+ */
73206
+ declare class BaseBreakoutPoint<TProps extends ZodType = typeof baseBreakoutPointProps> extends PrimitiveComponent<TProps> {
73062
73207
  pcb_breakout_point_id: string | null;
73063
73208
  matchedPort: Port | null;
73064
73209
  matchedNet: Net | null;
73065
73210
  isPcbPrimitive: boolean;
73211
+ _getSourceTraceIdForPort(port: Port): string | undefined;
73212
+ _getSourceNetIdForPort(port: Port): string | undefined;
73213
+ _renderPcbBreakoutPoint(): void;
73214
+ _getPcbCircuitJsonBounds(): {
73215
+ center: {
73216
+ x: number;
73217
+ y: number;
73218
+ };
73219
+ bounds: {
73220
+ left: number;
73221
+ top: number;
73222
+ right: number;
73223
+ bottom: number;
73224
+ };
73225
+ width: number;
73226
+ height: number;
73227
+ };
73228
+ _setPositionFromLayout(newCenter: {
73229
+ x: number;
73230
+ y: number;
73231
+ }): void;
73232
+ _moveCircuitJsonElements({ deltaX, deltaY, }: {
73233
+ deltaX: number;
73234
+ deltaY: number;
73235
+ }): void;
73236
+ getPcbSize(): {
73237
+ width: number;
73238
+ height: number;
73239
+ };
73240
+ }
73241
+
73242
+ declare class BreakoutPoint extends BaseBreakoutPoint<typeof breakoutPointProps> {
73066
73243
  get config(): {
73067
73244
  componentName: string;
73068
73245
  zodProps: zod.ZodObject<Omit<{
@@ -73199,35 +73376,7 @@ declare class BreakoutPoint extends PrimitiveComponent<typeof breakoutPointProps
73199
73376
  }>;
73200
73377
  };
73201
73378
  _matchConnection(): void;
73202
- _getSourceTraceIdForPort(port: Port): string | undefined;
73203
- _getSourceNetIdForPort(port: Port): string | undefined;
73204
73379
  doInitialPcbPrimitiveRender(): void;
73205
- _getPcbCircuitJsonBounds(): {
73206
- center: {
73207
- x: number;
73208
- y: number;
73209
- };
73210
- bounds: {
73211
- left: number;
73212
- top: number;
73213
- right: number;
73214
- bottom: number;
73215
- };
73216
- width: number;
73217
- height: number;
73218
- };
73219
- _setPositionFromLayout(newCenter: {
73220
- x: number;
73221
- y: number;
73222
- }): void;
73223
- _moveCircuitJsonElements({ deltaX, deltaY, }: {
73224
- deltaX: number;
73225
- deltaY: number;
73226
- }): void;
73227
- getPcbSize(): {
73228
- width: number;
73229
- height: number;
73230
- };
73231
73380
  }
73232
73381
 
73233
73382
  declare class Hole extends PrimitiveComponent<typeof holeProps> {
package/dist/index.js CHANGED
@@ -364,6 +364,7 @@ var orderedRenderPhases = [
364
364
  "PcbLayout",
365
365
  "PcbBoardAutoSize",
366
366
  "PanelLayout",
367
+ "PcbAutoplaceBreakoutPoints",
367
368
  "PcbTraceHintRender",
368
369
  "PcbManualTraceRender",
369
370
  "PcbTraceRender",
@@ -21806,7 +21807,7 @@ import { identity as identity5 } from "transformation-matrix";
21806
21807
  var package_default = {
21807
21808
  name: "@tscircuit/core",
21808
21809
  type: "module",
21809
- version: "0.0.1272",
21810
+ version: "0.0.1274",
21810
21811
  types: "dist/index.d.ts",
21811
21812
  main: "dist/index.js",
21812
21813
  module: "dist/index.js",
@@ -21838,6 +21839,7 @@ var package_default = {
21838
21839
  "@biomejs/biome": "^1.8.3",
21839
21840
  "@resvg/resvg-js": "^2.6.2",
21840
21841
  "@tscircuit/alphabet": "0.0.25",
21842
+ "@tscircuit/breakout-point-solver": "github:tscircuit/breakout-point-solver#bac9629",
21841
21843
  "@tscircuit/capacity-autorouter": "^0.0.529",
21842
21844
  "@tscircuit/checks": "0.0.133",
21843
21845
  "@tscircuit/circuit-json-util": "^0.0.94",
@@ -21879,7 +21881,7 @@ var package_default = {
21879
21881
  debug: "^4.3.6",
21880
21882
  "eecircuit-engine": "^1.5.6",
21881
21883
  flatbush: "^4.5.0",
21882
- "graphics-debug": "^0.0.89",
21884
+ "graphics-debug": "^0.0.95",
21883
21885
  howfat: "^0.3.8",
21884
21886
  "kicad-to-circuit-json": "^0.0.60",
21885
21887
  kicadts: "^0.0.35",
@@ -24803,63 +24805,19 @@ var PcbNoteDimension = class extends PrimitiveComponent2 {
24803
24805
 
24804
24806
  // lib/components/primitive-components/Breakout/Breakout.ts
24805
24807
  import "@tscircuit/props";
24806
- var Breakout = class extends Group5 {
24807
- constructor(props) {
24808
- super({
24809
- ...props,
24810
- // @ts-ignore
24811
- subcircuit: true
24812
- });
24813
- }
24814
- doInitialPcbPrimitiveRender() {
24815
- super.doInitialPcbPrimitiveRender();
24816
- if (this.root?.pcbDisabled) return;
24817
- const { db } = this.root;
24818
- const props = this._parsedProps;
24819
- if (!this.pcb_group_id) return;
24820
- const pcb_group = db.pcb_group.get(this.pcb_group_id);
24821
- const padLeft = props.paddingLeft ?? props.padding ?? 0;
24822
- const padRight = props.paddingRight ?? props.padding ?? 0;
24823
- const padTop = props.paddingTop ?? props.padding ?? 0;
24824
- const padBottom = props.paddingBottom ?? props.padding ?? 0;
24825
- db.pcb_group.update(this.pcb_group_id, {
24826
- width: (pcb_group.width ?? 0) + padLeft + padRight,
24827
- height: (pcb_group.height ?? 0) + padTop + padBottom,
24828
- center: {
24829
- x: pcb_group.center.x + (padRight - padLeft) / 2,
24830
- y: pcb_group.center.y + (padTop - padBottom) / 2
24831
- }
24832
- });
24833
- }
24834
- };
24808
+ import { BreakoutPointSolver } from "@tscircuit/breakout-point-solver";
24835
24809
 
24836
- // lib/components/primitive-components/BreakoutPoint.ts
24837
- import { breakoutPointProps } from "@tscircuit/props";
24838
- var BreakoutPoint = class extends PrimitiveComponent2 {
24810
+ // lib/components/primitive-components/BaseBreakoutPoint.ts
24811
+ import { pcbLayoutProps } from "@tscircuit/props";
24812
+ var baseBreakoutPointProps = pcbLayoutProps.omit({
24813
+ pcbRotation: true,
24814
+ layer: true
24815
+ });
24816
+ var BaseBreakoutPoint = class extends PrimitiveComponent2 {
24839
24817
  pcb_breakout_point_id = null;
24840
24818
  matchedPort = null;
24841
24819
  matchedNet = null;
24842
24820
  isPcbPrimitive = true;
24843
- get config() {
24844
- return {
24845
- componentName: "BreakoutPoint",
24846
- zodProps: breakoutPointProps
24847
- };
24848
- }
24849
- _matchConnection() {
24850
- const { connection } = this._parsedProps;
24851
- const subcircuit = this.getSubcircuit();
24852
- if (!subcircuit) return;
24853
- this.matchedPort = subcircuit.selectOne(connection, {
24854
- type: "port"
24855
- });
24856
- if (!this.matchedPort) {
24857
- this.matchedNet = subcircuit.selectOne(connection, { type: "net" });
24858
- }
24859
- if (!this.matchedPort && !this.matchedNet) {
24860
- this.renderError(`Could not find connection target "${connection}"`);
24861
- }
24862
- }
24863
24821
  _getSourceTraceIdForPort(port) {
24864
24822
  const { db } = this.root;
24865
24823
  const trace = db.source_trace.list().find((st) => st.connected_source_port_ids.includes(port.source_port_id));
@@ -24870,10 +24828,10 @@ var BreakoutPoint = class extends PrimitiveComponent2 {
24870
24828
  const trace = db.source_trace.list().find((st) => st.connected_source_port_ids.includes(port.source_port_id));
24871
24829
  return trace?.connected_source_net_ids[0];
24872
24830
  }
24873
- doInitialPcbPrimitiveRender() {
24831
+ _renderPcbBreakoutPoint() {
24832
+ if (this.pcb_breakout_point_id) return;
24874
24833
  if (this.root?.pcbDisabled) return;
24875
24834
  const { db } = this.root;
24876
- this._matchConnection();
24877
24835
  const position = this._getGlobalPcbPositionBeforeLayout();
24878
24836
  const group = this.parent?.getGroup();
24879
24837
  const subcircuit = this.getSubcircuit();
@@ -24931,6 +24889,237 @@ var BreakoutPoint = class extends PrimitiveComponent2 {
24931
24889
  }
24932
24890
  };
24933
24891
 
24892
+ // lib/components/primitive-components/AutoplacedBreakoutPoint.ts
24893
+ var AutoplacedBreakoutPoint = class extends BaseBreakoutPoint {
24894
+ get config() {
24895
+ return {
24896
+ componentName: "AutoplacedBreakoutPoint",
24897
+ zodProps: baseBreakoutPointProps
24898
+ };
24899
+ }
24900
+ doInitialPcbPrimitiveRender() {
24901
+ this._renderPcbBreakoutPoint();
24902
+ }
24903
+ };
24904
+
24905
+ // lib/components/primitive-components/BreakoutPoint.ts
24906
+ import { breakoutPointProps } from "@tscircuit/props";
24907
+ var BreakoutPoint = class extends BaseBreakoutPoint {
24908
+ get config() {
24909
+ return {
24910
+ componentName: "BreakoutPoint",
24911
+ zodProps: breakoutPointProps
24912
+ };
24913
+ }
24914
+ _matchConnection() {
24915
+ if (this.matchedPort) return;
24916
+ const { connection } = this._parsedProps;
24917
+ const subcircuit = this.getSubcircuit();
24918
+ if (!subcircuit) return;
24919
+ this.matchedPort = subcircuit.selectOne(connection, {
24920
+ type: "port"
24921
+ });
24922
+ if (!this.matchedPort) {
24923
+ this.matchedNet = subcircuit.selectOne(connection, { type: "net" });
24924
+ }
24925
+ if (!this.matchedPort && !this.matchedNet) {
24926
+ this.renderError(`Could not find connection target "${connection}"`);
24927
+ }
24928
+ }
24929
+ doInitialPcbPrimitiveRender() {
24930
+ this._matchConnection();
24931
+ this._renderPcbBreakoutPoint();
24932
+ }
24933
+ };
24934
+
24935
+ // lib/components/primitive-components/Breakout/createBreakoutPointSolverInput.ts
24936
+ import {
24937
+ findBoundsAndCenter
24938
+ } from "@tscircuit/circuit-json-util";
24939
+ var getPortLabel = (db, sourcePortId) => {
24940
+ if (!sourcePortId) return void 0;
24941
+ const sourcePort = db.source_port.get(sourcePortId);
24942
+ const sourceComponent = sourcePort?.source_component_id ? db.source_component.get(sourcePort.source_component_id) : void 0;
24943
+ if (!sourcePort) return void 0;
24944
+ return sourceComponent?.name ? `${sourceComponent.name}.${sourcePort.name}` : sourcePort.name;
24945
+ };
24946
+ var getPadElement = (db, pcbPortId) => {
24947
+ return db.pcb_smtpad.getWhere({ pcb_port_id: pcbPortId }) ?? db.pcb_plated_hole.getWhere({ pcb_port_id: pcbPortId });
24948
+ };
24949
+ var toBreakoutPort = (db, pcbPort) => {
24950
+ const pad = getPadElement(db, pcbPort.pcb_port_id);
24951
+ const padBounds = pad ? findBoundsAndCenter([pad]) : null;
24952
+ return {
24953
+ sourcePortId: pcbPort.source_port_id,
24954
+ position: { x: pcbPort.x, y: pcbPort.y },
24955
+ ...padBounds ? { width: padBounds.width, height: padBounds.height } : {},
24956
+ layer: pcbPort.layers?.[0] ?? "top",
24957
+ label: getPortLabel(db, pcbPort.source_port_id)
24958
+ };
24959
+ };
24960
+ var createBreakoutPointSolverInput = (breakout) => {
24961
+ if (!breakout.root || !breakout.pcb_group_id) return null;
24962
+ const { db } = breakout.root;
24963
+ const pcbGroup = db.pcb_group.get(breakout.pcb_group_id);
24964
+ if (!pcbGroup || !pcbGroup.width || !pcbGroup.height) return null;
24965
+ const sourcePortIdToPcbPort = /* @__PURE__ */ new Map();
24966
+ for (const pcbPort of db.pcb_port.list()) {
24967
+ if (!pcbPort.source_port_id) continue;
24968
+ sourcePortIdToPcbPort.set(pcbPort.source_port_id, pcbPort);
24969
+ }
24970
+ const boundsMinX = pcbGroup.center.x - pcbGroup.width / 2;
24971
+ const boundsMaxX = pcbGroup.center.x + pcbGroup.width / 2;
24972
+ const boundsMinY = pcbGroup.center.y - pcbGroup.height / 2;
24973
+ const boundsMaxY = pcbGroup.center.y + pcbGroup.height / 2;
24974
+ const traces = [];
24975
+ for (const sourceTrace of db.source_trace.list()) {
24976
+ const pcbPorts = sourceTrace.connected_source_port_ids.map((sourcePortId) => sourcePortIdToPcbPort.get(sourcePortId)).filter((port) => Boolean(port));
24977
+ const insidePorts = pcbPorts.filter(
24978
+ (port) => port.pcb_group_id === breakout.pcb_group_id
24979
+ );
24980
+ const outsidePorts = pcbPorts.filter(
24981
+ (port) => port.pcb_group_id !== breakout.pcb_group_id && !(port.x >= boundsMinX && port.x <= boundsMaxX && port.y >= boundsMinY && port.y <= boundsMaxY)
24982
+ );
24983
+ if (insidePorts.length === 0 || outsidePorts.length === 0) continue;
24984
+ traces.push({
24985
+ sourceTraceId: sourceTrace.source_trace_id,
24986
+ insidePorts: insidePorts.map((port) => toBreakoutPort(db, port)),
24987
+ outsidePorts: outsidePorts.map((port) => toBreakoutPort(db, port))
24988
+ });
24989
+ }
24990
+ if (traces.length === 0) return null;
24991
+ const allPadElements = [...db.pcb_smtpad.list(), ...db.pcb_plated_hole.list()];
24992
+ const pads = [];
24993
+ for (const pad of allPadElements) {
24994
+ const padBounds = findBoundsAndCenter([pad]);
24995
+ if (!padBounds.width || !padBounds.height) continue;
24996
+ const pcbPort = pad.pcb_port_id ? db.pcb_port.get(pad.pcb_port_id) : null;
24997
+ pads.push({
24998
+ center: padBounds.center,
24999
+ width: padBounds.width,
25000
+ height: padBounds.height,
25001
+ layer: pad.layer ?? "top",
25002
+ sourcePortIds: pcbPort?.source_port_id ? [pcbPort.source_port_id] : [],
25003
+ label: getPortLabel(db, pcbPort?.source_port_id)
25004
+ });
25005
+ }
25006
+ const components = db.pcb_component.list().filter((component) => component.width && component.height).map((component) => ({
25007
+ center: component.center,
25008
+ width: component.width,
25009
+ height: component.height,
25010
+ ccwRotationDegrees: component.rotation,
25011
+ layer: component.layer,
25012
+ label: component.pcb_component_id
25013
+ }));
25014
+ const usedBoundaryPoints = db.pcb_breakout_point.list().filter((point6) => point6.pcb_group_id === breakout.pcb_group_id).map((point6) => ({ x: point6.x, y: point6.y }));
25015
+ return {
25016
+ bounds: {
25017
+ minX: boundsMinX,
25018
+ maxX: boundsMaxX,
25019
+ minY: boundsMinY,
25020
+ maxY: boundsMaxY
25021
+ },
25022
+ boundaryPointSpacing: 0.5,
25023
+ traces,
25024
+ pads,
25025
+ components,
25026
+ usedBoundaryPoints
25027
+ };
25028
+ };
25029
+
25030
+ // lib/components/primitive-components/Breakout/Breakout.ts
25031
+ var Breakout = class extends Group5 {
25032
+ constructor(props) {
25033
+ super({
25034
+ ...props,
25035
+ // @ts-ignore
25036
+ subcircuit: true
25037
+ });
25038
+ }
25039
+ /**
25040
+ * Find ports inside this breakout group that are connected to traces
25041
+ * crossing the breakout boundary, and create auto-placed BreakoutPoint
25042
+ * children for them. Positions are not set here — they will be determined
25043
+ * after PcbLayout.
25044
+ */
25045
+ doInitialCreateAutoplacedBreakoutPoints() {
25046
+ const portsInBreakout = this.selectAll("port");
25047
+ const breakoutPortSet = new Set(portsInBreakout);
25048
+ const manualBreakoutPoints = this.children.filter(
25049
+ (c) => c instanceof BreakoutPoint
25050
+ );
25051
+ const manuallyMappedPorts = new Set(
25052
+ manualBreakoutPoints.map((bp) => {
25053
+ bp._matchConnection();
25054
+ return bp.matchedPort;
25055
+ }).filter(Boolean)
25056
+ );
25057
+ const board = this.parent;
25058
+ if (!board) return;
25059
+ const allTraces = board.children.filter(
25060
+ (c) => c instanceof Trace3
25061
+ );
25062
+ const autoPlacedPorts = /* @__PURE__ */ new Set();
25063
+ for (const trace of allTraces) {
25064
+ const result = trace._findConnectedPorts();
25065
+ if (!result.allPortsFound || !result.ports) continue;
25066
+ for (const port of result.ports) {
25067
+ const isInside = breakoutPortSet.has(port);
25068
+ const hasOutsidePort = result.ports.some((p) => !breakoutPortSet.has(p));
25069
+ if (!isInside || !hasOutsidePort) continue;
25070
+ if (manuallyMappedPorts.has(port)) continue;
25071
+ if (autoPlacedPorts.has(port)) continue;
25072
+ autoPlacedPorts.add(port);
25073
+ const breakoutPoint = new AutoplacedBreakoutPoint({});
25074
+ breakoutPoint.matchedPort = port;
25075
+ this.add(breakoutPoint);
25076
+ }
25077
+ }
25078
+ }
25079
+ doInitialPcbAutoplaceBreakoutPoints() {
25080
+ if (this.root?.pcbDisabled) return;
25081
+ const solverInput = createBreakoutPointSolverInput(this);
25082
+ if (!solverInput) return;
25083
+ const solver = new BreakoutPointSolver(solverInput);
25084
+ solver.solve();
25085
+ const output = solver.getOutput();
25086
+ const autoBreakoutPoints = this.children.filter(
25087
+ (c) => c instanceof AutoplacedBreakoutPoint
25088
+ );
25089
+ for (const solvedPoint of output.breakoutPoints) {
25090
+ const matchingBreakoutPoint = autoBreakoutPoints.find(
25091
+ (child) => child.matchedPort?.source_port_id === solvedPoint.sourcePortId
25092
+ );
25093
+ if (matchingBreakoutPoint) {
25094
+ matchingBreakoutPoint._setPositionFromLayout({
25095
+ x: solvedPoint.x,
25096
+ y: solvedPoint.y
25097
+ });
25098
+ }
25099
+ }
25100
+ }
25101
+ doInitialPcbPrimitiveRender() {
25102
+ super.doInitialPcbPrimitiveRender();
25103
+ if (this.root?.pcbDisabled) return;
25104
+ const { db } = this.root;
25105
+ const props = this._parsedProps;
25106
+ if (!this.pcb_group_id) return;
25107
+ const pcb_group = db.pcb_group.get(this.pcb_group_id);
25108
+ const padLeft = props.paddingLeft ?? props.padding ?? 0;
25109
+ const padRight = props.paddingRight ?? props.padding ?? 0;
25110
+ const padTop = props.paddingTop ?? props.padding ?? 0;
25111
+ const padBottom = props.paddingBottom ?? props.padding ?? 0;
25112
+ db.pcb_group.update(this.pcb_group_id, {
25113
+ width: (pcb_group.width ?? 0) + padLeft + padRight,
25114
+ height: (pcb_group.height ?? 0) + padTop + padBottom,
25115
+ center: {
25116
+ x: pcb_group.center.x + (padRight - padLeft) / 2,
25117
+ y: pcb_group.center.y + (padTop - padBottom) / 2
25118
+ }
25119
+ });
25120
+ }
25121
+ };
25122
+
24934
25123
  // lib/components/primitive-components/NetLabel.ts
24935
25124
  import { netLabelProps } from "@tscircuit/props";
24936
25125
  import {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.1273",
4
+ "version": "0.0.1275",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -33,6 +33,7 @@
33
33
  "@biomejs/biome": "^1.8.3",
34
34
  "@resvg/resvg-js": "^2.6.2",
35
35
  "@tscircuit/alphabet": "0.0.25",
36
+ "@tscircuit/breakout-point-solver": "github:tscircuit/breakout-point-solver#bac9629",
36
37
  "@tscircuit/capacity-autorouter": "^0.0.529",
37
38
  "@tscircuit/checks": "0.0.133",
38
39
  "@tscircuit/circuit-json-util": "^0.0.94",
@@ -74,7 +75,7 @@
74
75
  "debug": "^4.3.6",
75
76
  "eecircuit-engine": "^1.5.6",
76
77
  "flatbush": "^4.5.0",
77
- "graphics-debug": "^0.0.89",
78
+ "graphics-debug": "^0.0.95",
78
79
  "howfat": "^0.3.8",
79
80
  "kicad-to-circuit-json": "^0.0.60",
80
81
  "kicadts": "^0.0.35",