@tscircuit/props 0.0.618 → 0.0.619

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.
@@ -38,6 +38,27 @@ export interface CadModelBase {
38
38
  y: number | string
39
39
  z: number | string
40
40
  }
41
+ /**
42
+ * Axis-aligned extent of the model measured in its own coordinate frame, the
43
+ * same frame as `modelOriginPosition`.
44
+ *
45
+ * `size` gives the extent but not where the box sits relative to the model
46
+ * origin, and the box is generally not centered on it, so `size` alone cannot
47
+ * say how much of the part is above the board. Since `modelOriginPosition` is
48
+ * the point placed on the board surface, these bounds supply the missing
49
+ * term. `modelBoardNormalDirection` names the axis (default `z+`): for a
50
+ * positive normal the outward reach is `max[axis] - origin[axis]`, and for a
51
+ * negative one it is `origin[axis] - min[axis]`.
52
+ *
53
+ * These are the model's own bounds, before `modelUnitToMmScale` or any
54
+ * object-fit scaling is applied.
55
+ *
56
+ * Whatever generates a part file already measures this to produce `size`.
57
+ */
58
+ modelBounds?: {
59
+ min: { x: number | string; y: number | string; z: number | string }
60
+ max: { x: number | string; y: number | string; z: number | string }
61
+ }
41
62
  size?: { x: number | string; y: number | string; z: number | string }
42
63
  modelUnitToMmScale?: Distance
43
64
  modelBoardNormalDirection?: CadModelAxisDirection
@@ -51,6 +72,7 @@ export const cadModelBase = z.object({
51
72
  rotationOffset: z.number().or(rotationPoint3).optional(),
52
73
  positionOffset: point3.optional(),
53
74
  modelOriginPosition: point3.optional(),
75
+ modelBounds: z.object({ min: point3, max: point3 }).optional(),
54
76
  size: point3.optional(),
55
77
  modelUnitToMmScale: distance.optional(),
56
78
  modelBoardNormalDirection: cadModelAxisDirection.optional(),
@@ -81,6 +81,26 @@ export interface FootprintProps {
81
81
  * makes the distinction easy to miss.
82
82
  */
83
83
  insertionDirection?: FootprintInsertionDirection
84
+ /**
85
+ * Direction the part's enclosure opening faces, named the same way as
86
+ * `insertionDirection` and in the same unrotated part frame.
87
+ *
88
+ * These are two different physical facts and a part may need both. A
89
+ * side-actuated switch is *installed* from above and *actuated* from the side:
90
+ * its aperture must pierce a side wall, while nothing is ever inserted into
91
+ * it. Reusing `insertionDirection` for that would either put the opening on
92
+ * the wrong face or overload a field documented as "the side exposing the
93
+ * receptacle where the cable is attached".
94
+ *
95
+ * Like `insertionDirection`, this is a property of the part, authored without
96
+ * regard to placement: rotating or flipping the component rotates it too, and
97
+ * `pcb_component.cutout_aperture_direction` reports the result in board
98
+ * coordinates.
99
+ *
100
+ * When absent, the aperture falls back to `insertionDirection`, which is
101
+ * correct for every connector -- a cable enters through the opening it needs.
102
+ */
103
+ cutoutApertureDirection?: FootprintInsertionDirection
84
104
  }
85
105
 
86
106
  export const footprintProps = z.object({
@@ -94,6 +114,11 @@ export const footprintProps = z.object({
94
114
  .describe(
95
115
  "Direction a cable or mating part is attached from, named for the side of the footprint it approaches from, in its unrotated orientation.",
96
116
  ),
117
+ cutoutApertureDirection: footprintInsertionDirection
118
+ .optional()
119
+ .describe(
120
+ "Direction the part's enclosure opening faces, in its unrotated orientation. Distinct from insertionDirection: a side-actuated switch is installed from above and actuated from the side. Falls back to insertionDirection when absent.",
121
+ ),
97
122
  })
98
123
 
99
124
  export type FootprintPropsInput = z.input<typeof footprintProps>
@@ -19,30 +19,91 @@ export type EnclosureCutoutApertureShape = CommonShapeProps["shape"]
19
19
  * Describes the nominal enclosure opening required by a component.
20
20
  *
21
21
  * Numeric values are interpreted as mm.
22
+ *
23
+ * ## Frame of reference
24
+ *
25
+ * An aperture is authored around the owning part's interaction axis, derived
26
+ * from its footprint `cutoutApertureDirection` or `insertionDirection`. On a
27
+ * side opening, `height` is board Z, `width` is perpendicular to that axis in
28
+ * the board plane, and `depth` follows the axis inboard. On the lid or floor,
29
+ * width and height rotate in-plane with the footprint and depth is vertical.
30
+ *
31
+ * The enclosure face is resolved later from where the transformed axis first
32
+ * intersects the box; it supplies a material plane, not the aperture's original
33
+ * coordinate frame.
22
34
  */
23
- export interface PillEnclosureCutoutApertureProps extends PillShapeProps {
35
+ export interface CutoutApertureProps {
24
36
  /** Additional clearance around the nominal opening. */
25
37
  margin?: Distance
38
+ /**
39
+ * Move the opening's **center** across the face it pierces, along the same two
40
+ * axes its `width` and `height` are measured in. Both may be negative.
41
+ *
42
+ * Sharing a frame with the dimensions is the point. These replace
43
+ * `zExtentAboveBoard`, which only made sense on the four walls: on the lid and
44
+ * the floor an opening does not move in Z at all, so a "Z extent" had no
45
+ * meaning there.
46
+ *
47
+ * Zero means "wherever the part puts it", which is usually right. On a side
48
+ * face the opening is centred on the part's body above the board, taken from
49
+ * the model's measured bounds, so it lines up with the connector without
50
+ * anyone computing a height. On the lid or the floor it is centred on the
51
+ * part's own position, and both offsets turn with the part.
52
+ *
53
+ * `heightDimensionOffset` runs **outward** from the mounting surface on a side
54
+ * face -- up for a top-mounted part, down for a bottom-mounted one -- so, like
55
+ * the default it shifts, it describes the part rather than where the part was
56
+ * placed. A negative value pulls the opening back toward and past the board,
57
+ * which is what a cable jacket fatter than its connector needs; the binding
58
+ * constraint is that the opening must not cut into the floor.
59
+ */
60
+ widthDimensionOffset?: Distance
61
+ /** See `widthDimensionOffset`. */
62
+ heightDimensionOffset?: Distance
63
+ /**
64
+ * How far the cutting tool continues inboard along the part's interaction
65
+ * axis, so the lid lip or other material behind the wall cannot obstruct it.
66
+ * On a side opening this axis may be oblique to X/Y; on the lid or floor it is
67
+ * vertical. The profile is cut as authored and never capped, so an explicitly
68
+ * excessive depth can reach the shell on the far side.
69
+ *
70
+ * Usually unnecessary: side depth is derived from the rotated CAD-body/PCB
71
+ * envelope. Horizontal depth uses the model's measured reach from the board
72
+ * and converts it to the cavity span beyond the plate's inner surface; where
73
+ * bounds are absent, `cadModel.size.z` is a less accurate fallback because it
74
+ * can include pins and through-board geometry.
75
+ *
76
+ * Set this where that envelope is wrong for the purpose -- for example a
77
+ * tapered body -- or where a part has no CAD model.
78
+ */
79
+ depth?: Distance
26
80
  }
27
81
 
28
- export interface RectEnclosureCutoutApertureProps extends RectShapeProps {
29
- /** Additional clearance around the nominal opening. */
30
- margin?: Distance
31
- }
82
+ export interface PillEnclosureCutoutApertureProps
83
+ extends PillShapeProps,
84
+ CutoutApertureProps {}
32
85
 
33
- export interface CircleEnclosureCutoutApertureProps extends CircleShapeProps {
34
- /** Additional clearance around the nominal opening. */
35
- margin?: Distance
36
- }
86
+ export interface RectEnclosureCutoutApertureProps
87
+ extends RectShapeProps,
88
+ CutoutApertureProps {}
89
+
90
+ export interface CircleEnclosureCutoutApertureProps
91
+ extends CircleShapeProps,
92
+ CutoutApertureProps {}
37
93
 
38
94
  export type EnclosureCutoutApertureProps =
39
95
  | PillEnclosureCutoutApertureProps
40
96
  | RectEnclosureCutoutApertureProps
41
97
  | CircleEnclosureCutoutApertureProps
42
98
 
43
- const apertureOnlyProps = {
99
+ export const cutoutApertureBaseProps = z.object({
44
100
  margin: distance.optional(),
45
- }
101
+ widthDimensionOffset: distance.optional(),
102
+ heightDimensionOffset: distance.optional(),
103
+ depth: distance.optional(),
104
+ })
105
+
106
+ const apertureOnlyProps = cutoutApertureBaseProps.shape
46
107
 
47
108
  export const enclosureCutoutApertureProps = z.discriminatedUnion("shape", [
48
109
  pillShapeProps.extend(apertureOnlyProps),
@@ -50,10 +111,11 @@ export const enclosureCutoutApertureProps = z.discriminatedUnion("shape", [
50
111
  circleShapeProps.extend(apertureOnlyProps),
51
112
  ])
52
113
 
53
- type InferredEnclosureCutoutApertureProps = z.input<
114
+ export type ParsedEnclosureCutoutApertureProps = z.output<
54
115
  typeof enclosureCutoutApertureProps
55
116
  >
56
- export type ParsedEnclosureCutoutApertureProps = z.output<
117
+
118
+ type InferredEnclosureCutoutApertureProps = z.input<
57
119
  typeof enclosureCutoutApertureProps
58
120
  >
59
121
 
@@ -3,20 +3,60 @@ import { expectTypesMatch } from "lib/typecheck"
3
3
  import { z } from "zod"
4
4
 
5
5
  export interface EnclosureFdmBoxProps {
6
+ /** Stable enclosure identity. */
7
+ name?: string
6
8
  /** The name or selector of the board enclosed by this box. */
7
9
  boardRef: string
10
+ /** Optional outside X dimension; inferred from the board when omitted. */
8
11
  width?: Distance
12
+ /** Optional outside Y dimension; inferred from the board when omitted. */
9
13
  height?: Distance
14
+ /** Optional total outside Z dimension; inferred from the board stack. */
10
15
  depth?: Distance
16
+ /** Printed side-wall thickness. */
11
17
  wallThickness?: Distance
18
+ /** Base floor thickness. */
19
+ floorThickness?: Distance
20
+ /** Lid top-plate thickness. */
21
+ lidThickness?: Distance
22
+ /** Horizontal clearance between the board edge and inside wall. */
23
+ boardClearance?: Distance
24
+ /** Gap from the inside floor to the PCB bottom. */
25
+ standoffHeight?: Distance
26
+ /**
27
+ * Clearance from the PCB top surface up to the inside of the lid.
28
+ *
29
+ * This is measured from the *board*, not from the tallest component: only
30
+ * parts that declare an aperture report their height, so an arbitrary tall
31
+ * capacitor is invisible here and setting this does not guarantee it clears.
32
+ *
33
+ * Omit it and the depth is inferred instead -- grown until the lid and its lip
34
+ * clear every side-wall aperture, so a connector taller than the default
35
+ * cannot end up straddling the base/lid seam. Setting it explicitly opts out
36
+ * of that: the value is then taken literally, which is what allows a part to
37
+ * deliberately poke through the lid.
38
+ */
39
+ topHeadroom?: Distance
40
+ /** Depth of the friction-fit lid lip. */
41
+ lidLipDepth?: Distance
42
+ /** Disable placement of apertures explicitly declared by enclosed components. */
43
+ disableCutouts?: boolean
12
44
  }
13
45
 
14
46
  export const enclosureFdmBoxProps = z.object({
47
+ name: z.string().optional(),
15
48
  boardRef: z.string().min(1),
16
49
  width: distance.optional(),
17
50
  height: distance.optional(),
18
51
  depth: distance.optional(),
19
52
  wallThickness: distance.default("2mm"),
53
+ floorThickness: distance.optional(),
54
+ lidThickness: distance.optional(),
55
+ boardClearance: distance.optional(),
56
+ standoffHeight: distance.optional(),
57
+ topHeadroom: distance.optional(),
58
+ lidLipDepth: distance.optional(),
59
+ disableCutouts: z.boolean().optional(),
20
60
  })
21
61
 
22
62
  export type EnclosureFdmBoxPropsInput = z.input<typeof enclosureFdmBoxProps>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/props",
3
- "version": "0.0.618",
3
+ "version": "0.0.619",
4
4
  "description": "Props for tscircuit builtin component types",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",