@tscircuit/props 0.0.707 → 0.0.709

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.
@@ -0,0 +1,15 @@
1
+ import { assemblyDrawingTitleBlockProps } from "./titleblock"
2
+ import { assemblyDrawingPageProps } from "./page"
3
+ import { assemblyDrawingPartViewProps } from "./partview"
4
+
5
+ export * from "./page"
6
+ export * from "./page-size"
7
+ export * from "./titleblock"
8
+ export * from "./partview"
9
+
10
+ /** Drawing namespace; pages contain configured part views. */
11
+ export const assemblyDrawingProps = {
12
+ page: assemblyDrawingPageProps,
13
+ titleblock: assemblyDrawingTitleBlockProps,
14
+ partview: assemblyDrawingPartViewProps,
15
+ } as const
@@ -0,0 +1,37 @@
1
+ import { z } from "zod"
2
+
3
+ /** Landscape dimensions in mm. ISO A-series / ASME Y14.1 decimal-inch sheets. */
4
+ export const assemblyDrawingPageSizes = {
5
+ iso_a0: [1189, 841],
6
+ iso_a1: [841, 594],
7
+ iso_a2: [594, 420],
8
+ iso_a3: [420, 297],
9
+ iso_a4: [297, 210],
10
+ ansi_a: [279.4, 215.9],
11
+ ansi_b: [431.8, 279.4],
12
+ ansi_c: [558.8, 431.8],
13
+ ansi_d: [863.6, 558.8],
14
+ ansi_e: [1117.6, 863.6],
15
+ } as const
16
+ export const assemblyDrawingPageSize = z.enum([
17
+ "iso_a0",
18
+ "iso_a1",
19
+ "iso_a2",
20
+ "iso_a3",
21
+ "iso_a4",
22
+ "ansi_a",
23
+ "ansi_b",
24
+ "ansi_c",
25
+ "ansi_d",
26
+ "ansi_e",
27
+ ])
28
+ export type AssemblyDrawingPageSize = z.infer<typeof assemblyDrawingPageSize>
29
+ export function getAssemblyDrawingPageDimensions(
30
+ size: AssemblyDrawingPageSize,
31
+ orientation: "landscape" | "portrait" = "landscape",
32
+ ) {
33
+ const [width, height] = assemblyDrawingPageSizes[size]
34
+ return orientation === "portrait"
35
+ ? { width: height, height: width }
36
+ : { width, height }
37
+ }
@@ -0,0 +1,64 @@
1
+ import { z } from "zod"
2
+ import {
3
+ assemblyDrawingPageSize,
4
+ getAssemblyDrawingPageDimensions,
5
+ type AssemblyDrawingPageSize,
6
+ } from "./page-size"
7
+ import { distance } from "circuit-json"
8
+ import type { Distance } from "lib/common/distance"
9
+ import { expectTypesMatch } from "lib/typecheck"
10
+
11
+ /** A paper-space drawing page containing configured part views. */
12
+ export interface AssemblyDrawingPageProps {
13
+ name?: string
14
+ displayName?: string
15
+ /** Standard sheet size; landscape by default. Mutually exclusive with width/height. */
16
+ size?: AssemblyDrawingPageSize
17
+ orientation?: "landscape" | "portrait"
18
+ /** Custom paper dimensions in mm when numeric; unit strings are accepted. */
19
+ width?: Distance
20
+ height?: Distance
21
+ children?: any
22
+ }
23
+
24
+ export const assemblyDrawingPageProps = z
25
+ .object({
26
+ name: z.string().optional(),
27
+ displayName: z.string().optional(),
28
+ size: assemblyDrawingPageSize.optional(),
29
+ orientation: z.enum(["landscape", "portrait"]).optional(),
30
+ width: distance.pipe(z.number().finite().positive()).optional(),
31
+ height: distance.pipe(z.number().finite().positive()).optional(),
32
+ children: z.any().optional(),
33
+ })
34
+ .superRefine((page, ctx) => {
35
+ if (
36
+ page.size
37
+ ? page.width != null || page.height != null
38
+ : page.width == null || page.height == null
39
+ )
40
+ ctx.addIssue({
41
+ code: "custom",
42
+ message: "Specify size or both width and height, exclusively",
43
+ })
44
+ if (!page.size && page.orientation)
45
+ ctx.addIssue({
46
+ code: "custom",
47
+ path: ["orientation"],
48
+ message: "Orientation requires a standard size",
49
+ })
50
+ })
51
+ .transform((page) => ({
52
+ ...page,
53
+ ...(page.size
54
+ ? getAssemblyDrawingPageDimensions(page.size, page.orientation)
55
+ : { width: page.width!, height: page.height! }),
56
+ }))
57
+
58
+ export type InferredAssemblyDrawingPageProps = z.input<
59
+ typeof assemblyDrawingPageProps
60
+ >
61
+ expectTypesMatch<
62
+ AssemblyDrawingPageProps,
63
+ z.input<typeof assemblyDrawingPageProps>
64
+ >(true)
@@ -0,0 +1,118 @@
1
+ import { z } from "zod"
2
+ import { distance } from "circuit-json"
3
+ import type { Distance } from "lib/common/distance"
4
+ import { expectTypesMatch } from "lib/typecheck"
5
+
6
+ /** Axis names use tscircuit CAD coordinates: mm, +Z up. The camera sits on
7
+ * the named side of the model and looks toward its center. */
8
+ export type AssemblyDrawingPartViewDirection =
9
+ | "x+"
10
+ | "x-"
11
+ | "y+"
12
+ | "y-"
13
+ | "z+"
14
+ | "z-"
15
+ | "isometric"
16
+
17
+ export interface AssemblyDrawingSectionPlane {
18
+ axis: "x" | "y" | "z"
19
+ /** Plane coordinate in CAD world space, numeric mm or a distance string. */
20
+ offset: Distance
21
+ /** Retain coordinates <= offset or >= offset, respectively. */
22
+ keepSide: "less" | "greater"
23
+ /** Physical distance between 45-degree strokes on the model. Defaults to 1mm. */
24
+ hatchSpacing?: Distance
25
+ }
26
+
27
+ export const assemblyDrawingSectionPlane = z.object({
28
+ axis: z.enum(["x", "y", "z"]),
29
+ offset: distance.pipe(z.number().finite()),
30
+ keepSide: z.enum(["less", "greater"]),
31
+ hatchSpacing: distance.pipe(z.number().finite().positive()).default(1),
32
+ })
33
+
34
+ /** An orthographic viewport within an assembly.drawing.page. */
35
+ export interface AssemblyDrawingPartViewProps {
36
+ name?: string
37
+ displayName?: string
38
+ /** Selector for the board, group or assembly geometry shown in this view. */
39
+ partRef: string
40
+ direction: AssemblyDrawingPartViewDirection
41
+ /** Viewport center relative to the paper center, mm; +X right, +Y up. Defaults to 0 on axes without a relative reference. */
42
+ centerX?: Distance
43
+ centerY?: Distance
44
+ /** Sibling part-view selector; infer centerX with this viewport left of the reference. Conflicts with rightOfRef and centerX. */
45
+ leftOfRef?: string
46
+ /** Sibling part-view selector; infer centerX with this viewport right of the reference. Conflicts with leftOfRef and centerX. */
47
+ rightOfRef?: string
48
+ /** Sibling part-view selector; infer centerY with this viewport above the reference. Conflicts with belowRef and centerY. */
49
+ aboveRef?: string
50
+ /** Sibling part-view selector; infer centerY with this viewport below the reference. Conflicts with aboveRef and centerY. */
51
+ belowRef?: string
52
+ /** Paper-space viewport size; dimensions must be positive. */
53
+ width: Distance
54
+ height: Distance
55
+ /** Draw obscured edges as dashed strokes. Defaults to false. */
56
+ showHiddenEdges?: boolean
57
+ /** A planar cut with diagonal hatching on closed cut surfaces. */
58
+ section?: AssemblyDrawingSectionPlane
59
+ }
60
+
61
+ export const assemblyDrawingPartViewProps = z
62
+ .object({
63
+ name: z.string().optional(),
64
+ displayName: z.string().optional(),
65
+ partRef: z.string().min(1),
66
+ direction: z.enum(["x+", "x-", "y+", "y-", "z+", "z-", "isometric"]),
67
+ centerX: distance.pipe(z.number().finite()).optional(),
68
+ centerY: distance.pipe(z.number().finite()).optional(),
69
+ leftOfRef: z.string().trim().min(1).optional(),
70
+ rightOfRef: z.string().trim().min(1).optional(),
71
+ aboveRef: z.string().trim().min(1).optional(),
72
+ belowRef: z.string().trim().min(1).optional(),
73
+ width: distance.pipe(z.number().finite().positive()),
74
+ height: distance.pipe(z.number().finite().positive()),
75
+ showHiddenEdges: z.boolean().default(false),
76
+ section: assemblyDrawingSectionPlane.optional(),
77
+ })
78
+ .superRefine((view, ctx) => {
79
+ for (const [center, negative, positive] of [
80
+ ["centerX", "leftOfRef", "rightOfRef"],
81
+ ["centerY", "belowRef", "aboveRef"],
82
+ ] as const) {
83
+ if (view[negative] !== undefined && view[positive] !== undefined)
84
+ ctx.addIssue({
85
+ code: "custom",
86
+ path: [positive],
87
+ message: `${negative} and ${positive} are mutually exclusive`,
88
+ })
89
+ if (
90
+ view[center] !== undefined &&
91
+ (view[negative] !== undefined || view[positive] !== undefined)
92
+ )
93
+ ctx.addIssue({
94
+ code: "custom",
95
+ path: [center],
96
+ message: `${center} cannot be combined with ${negative} or ${positive}`,
97
+ })
98
+ }
99
+ })
100
+ .transform((view) => ({
101
+ ...view,
102
+ ...(view.leftOfRef || view.rightOfRef
103
+ ? {}
104
+ : { centerX: view.centerX ?? 0 }),
105
+ ...(view.aboveRef || view.belowRef ? {} : { centerY: view.centerY ?? 0 }),
106
+ }))
107
+
108
+ export type InferredAssemblyDrawingPartViewProps = z.input<
109
+ typeof assemblyDrawingPartViewProps
110
+ >
111
+ expectTypesMatch<
112
+ AssemblyDrawingSectionPlane,
113
+ z.input<typeof assemblyDrawingSectionPlane>
114
+ >(true)
115
+ expectTypesMatch<
116
+ AssemblyDrawingPartViewProps,
117
+ z.input<typeof assemblyDrawingPartViewProps>
118
+ >(true)
@@ -0,0 +1,43 @@
1
+ import { z } from "zod"
2
+ import { expectTypesMatch } from "lib/typecheck"
3
+
4
+ /** Optional page child. Metadata fields reference ISO 7200:2004. */
5
+ export interface AssemblyDrawingTitleBlockProps {
6
+ name?: string
7
+ title: string
8
+ legalOwner?: string
9
+ identificationNumber?: string
10
+ revisionIndex?: string
11
+ dateOfIssue?: string
12
+ creator?: string
13
+ approvalPerson?: string
14
+ sheetNumber?: number
15
+ numberOfSheets?: number
16
+ }
17
+ export const assemblyDrawingTitleBlockProps = z
18
+ .object({
19
+ name: z.string().optional(),
20
+ title: z.string().min(1),
21
+ legalOwner: z.string().optional(),
22
+ identificationNumber: z.string().optional(),
23
+ revisionIndex: z.string().optional(),
24
+ dateOfIssue: z.string().optional(),
25
+ creator: z.string().optional(),
26
+ approvalPerson: z.string().optional(),
27
+ sheetNumber: z.number().int().positive().optional(),
28
+ numberOfSheets: z.number().int().positive().optional(),
29
+ })
30
+ .refine(
31
+ (block) =>
32
+ block.sheetNumber == null ||
33
+ block.numberOfSheets == null ||
34
+ block.sheetNumber <= block.numberOfSheets,
35
+ {
36
+ message: "sheetNumber must not exceed numberOfSheets",
37
+ path: ["sheetNumber"],
38
+ },
39
+ )
40
+ expectTypesMatch<
41
+ AssemblyDrawingTitleBlockProps,
42
+ z.input<typeof assemblyDrawingTitleBlockProps>
43
+ >(true)
@@ -1,3 +1,4 @@
1
+ import { assemblyDrawingProps } from "./drawing"
1
2
  import { assemblyCadAssemblyProps } from "./cadassembly"
2
3
  import { assemblyCableProps } from "./cable"
3
4
  import { assemblyBoltProps } from "./bolt"
@@ -11,6 +12,7 @@ import { assemblyScreenProps } from "./screen"
11
12
  import { assemblySubassemblyProps } from "./subassembly"
12
13
  import { assemblyExplosionProps } from "./explosion"
13
14
 
15
+ export * from "./drawing"
14
16
  export * from "./board-mounting"
15
17
  export * from "./bolt"
16
18
  export * from "./fastener"
@@ -26,6 +28,7 @@ export * from "./cadassembly"
26
28
  export * from "./explosion"
27
29
 
28
30
  export const assemblyProps = {
31
+ drawing: assemblyDrawingProps,
29
32
  explosion: assemblyExplosionProps,
30
33
  bolt: assemblyBoltProps,
31
34
  fastener: assemblyFastenerProps,
@@ -1,4 +1,4 @@
1
- import { ms } from "circuit-json"
1
+ import { frequency, length, ms } from "circuit-json"
2
2
  import { expectTypesMatch } from "lib/typecheck"
3
3
  import { z } from "zod"
4
4
  import { ibisPinRunState, type IbisPinRunState } from "lib/common/ibis"
@@ -17,8 +17,119 @@ export interface AnalogTransientSimulationProps
17
17
  timePerStep?: number | string
18
18
  /** Physical pin selectors and per-experiment direction/enable states. Requires spiceEngine="pcb_spice"; rendering only declares the experiment. */
19
19
  ibisPinStates?: Record<string, IbisPinRunState>
20
+ pcbSpiceChannel?: PcbSpiceChannelProps
20
21
  }
21
22
 
23
+ export interface PcbSpiceChannelProps {
24
+ reduction: "routed-copper" | "straightened-stages"
25
+ sections: number
26
+ lanes: Array<{ name: string; from: string; to: string }>
27
+ referencePinRef: string
28
+ passiveComponentRefs?: string[]
29
+ extraction: {
30
+ minimumFrequency: number | string
31
+ maximumFrequency: number | string
32
+ modelFrequency: number | string
33
+ filaments: number
34
+ refinementFilaments: number
35
+ convergenceTolerance: number
36
+ capacitanceTolerance: number
37
+ reciprocityTolerance: number
38
+ dcResistanceTolerance: number
39
+ maxPanelLength: number | string
40
+ groundMeshSize?: number | string
41
+ }
42
+ relativePermittivity?: number
43
+ via?: {
44
+ platingThickness?: number | string
45
+ equivalentWidth?: number | string
46
+ omitThroughViaStubs?: boolean
47
+ }
48
+ straightenedStageProfiles?: Record<
49
+ string,
50
+ {
51
+ spacing: number | string
52
+ relativePermittivity: number
53
+ return: {
54
+ width: number | string
55
+ thickness: number | string
56
+ lengthFactor: number
57
+ centerY: number | string
58
+ centerZ: number | string
59
+ }
60
+ }
61
+ >
62
+ }
63
+
64
+ const positiveLength = length.pipe(z.number().finite().positive())
65
+ const signedLength = length.pipe(z.number().finite())
66
+ const positiveFrequency = frequency.pipe(z.number().finite().positive())
67
+
68
+ export const pcbSpiceChannelProps = z.object({
69
+ reduction: z.enum(["routed-copper", "straightened-stages"]),
70
+ sections: z.number().int().min(1).max(128),
71
+ lanes: z
72
+ .array(
73
+ z.object({
74
+ name: z.string().min(1),
75
+ from: z.string().min(1),
76
+ to: z.string().min(1),
77
+ }),
78
+ )
79
+ .min(1)
80
+ .max(3),
81
+ referencePinRef: z.string().min(1),
82
+ passiveComponentRefs: z.array(z.string().min(1)).optional(),
83
+ extraction: z
84
+ .object({
85
+ minimumFrequency: positiveFrequency,
86
+ maximumFrequency: positiveFrequency,
87
+ modelFrequency: positiveFrequency,
88
+ filaments: z.number().int().positive(),
89
+ refinementFilaments: z.number().int().positive(),
90
+ convergenceTolerance: z.number().finite().positive(),
91
+ capacitanceTolerance: z.number().finite().positive(),
92
+ reciprocityTolerance: z.number().finite().positive(),
93
+ dcResistanceTolerance: z.number().finite().positive(),
94
+ maxPanelLength: positiveLength,
95
+ groundMeshSize: positiveLength.optional(),
96
+ })
97
+ .refine(
98
+ (extraction) => extraction.refinementFilaments > extraction.filaments,
99
+ {
100
+ path: ["refinementFilaments"],
101
+ message: "refinementFilaments must be greater than filaments",
102
+ },
103
+ ),
104
+ relativePermittivity: z.number().finite().positive().optional(),
105
+ via: z
106
+ .object({
107
+ platingThickness: positiveLength.optional(),
108
+ equivalentWidth: positiveLength.optional(),
109
+ omitThroughViaStubs: z.boolean().optional(),
110
+ })
111
+ .optional(),
112
+ straightenedStageProfiles: z
113
+ .record(
114
+ z.object({
115
+ spacing: positiveLength,
116
+ relativePermittivity: z.number().finite().positive(),
117
+ return: z.object({
118
+ width: positiveLength,
119
+ thickness: positiveLength,
120
+ lengthFactor: z.number().finite().positive(),
121
+ centerY: signedLength,
122
+ centerZ: signedLength,
123
+ }),
124
+ }),
125
+ )
126
+ .optional(),
127
+ })
128
+
129
+ expectTypesMatch<PcbSpiceChannelProps, z.input<typeof pcbSpiceChannelProps>>(
130
+ true,
131
+ )
132
+
22
133
  const positiveMilliseconds = ms.refine(
23
134
  (milliseconds) => milliseconds > 0,
24
135
  "Time must be positive",
@@ -30,9 +141,17 @@ export const analogTransientSimulationProps = z
30
141
  duration: positiveMilliseconds.default("10ms"),
31
142
  startTime: ms.default("0ms"),
32
143
  timePerStep: positiveMilliseconds.default("0.01ms"),
144
+ pcbSpiceChannel: pcbSpiceChannelProps.optional(),
33
145
  ibisPinStates: z.record(z.string().min(1), ibisPinRunState).optional(),
34
146
  })
35
147
  .superRefine((simulation, context) => {
148
+ if (simulation.pcbSpiceChannel && simulation.spiceEngine !== "pcb_spice") {
149
+ context.addIssue({
150
+ code: z.ZodIssueCode.custom,
151
+ path: ["pcbSpiceChannel"],
152
+ message: "PCB SPICE channel settings require spiceEngine=pcb_spice",
153
+ })
154
+ }
36
155
  if (simulation.ibisPinStates && simulation.spiceEngine !== "pcb_spice") {
37
156
  context.addIssue({
38
157
  code: z.ZodIssueCode.custom,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/props",
3
- "version": "0.0.707",
3
+ "version": "0.0.709",
4
4
  "description": "Props for tscircuit builtin component types",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",