@tscircuit/props 0.0.703 → 0.0.705

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,60 @@
1
+ import { asset } from "circuit-json"
2
+ import { z } from "zod"
3
+
4
+ /** Direction is explicit per experiment. Only outputs accept an enable state. */
5
+ export const ibisPinRunState = z.discriminatedUnion("isOutput", [
6
+ z.object({ isOutput: z.literal(false) }).strict(),
7
+ z
8
+ .object({ isOutput: z.literal(true), isOutputEnabled: z.boolean() })
9
+ .strict(),
10
+ ])
11
+ export type IbisPinRunState = z.input<typeof ibisPinRunState>
12
+
13
+ /** Reference values are labels on the same chip, never inferred supply rails. */
14
+ export const ibisPinReferences = z
15
+ .object({
16
+ pullup: z.string().min(1).optional(),
17
+ pulldown: z.string().min(1).optional(),
18
+ powerClamp: z.string().min(1).optional(),
19
+ groundClamp: z.string().min(1).optional(),
20
+ external: z.string().min(1).optional(),
21
+ })
22
+ .strict()
23
+ export type IbisPinReferences = z.input<typeof ibisPinReferences>
24
+
25
+ /** Same location rules as circuit-json's simulation_ibis_model asset. */
26
+ const ibisAssetPath = z
27
+ .string()
28
+ .min(1)
29
+ .regex(/^(?!\s|[a-z][a-z\d+.-]*:|[/\\])[^\\\u0000-\u001f\u007f]+$/i)
30
+
31
+ export const ibisModelAsset = asset.extend({
32
+ project_relative_path: ibisAssetPath,
33
+ url: z
34
+ .string()
35
+ .url()
36
+ .regex(/^https?:\/\//i)
37
+ .or(ibisAssetPath),
38
+ })
39
+
40
+ export const ibisModelDefinition = z.object({
41
+ ibisModelAsset,
42
+ ibisComponentName: z.string().min(1),
43
+ ibisPinNameToPortLabel: z
44
+ .record(z.string().min(1), z.string().min(1))
45
+ .refine((pins) => Object.keys(pins).length > 0),
46
+ ibisPinNameToModelName: z
47
+ .record(z.string().min(1), z.string().min(1))
48
+ .optional(),
49
+ ibisPinNameToReferencePortLabels: z
50
+ .record(z.string().min(1), ibisPinReferences)
51
+ .optional(),
52
+ modelValueCorner: z.union([
53
+ z.literal("typical"),
54
+ z.literal("minimum"),
55
+ z.literal("maximum"),
56
+ ]),
57
+ includePackageParasitics: z.boolean(),
58
+ })
59
+ /** Vendor [Component] and [Pin] names are bound explicitly to this chip's ports. No corner or package defaults are inferred. */
60
+ export type IbisModelDefinition = z.input<typeof ibisModelDefinition>
@@ -0,0 +1,60 @@
1
+ import { ms } from "circuit-json"
2
+ import { expectTypesMatch } from "lib/typecheck"
3
+ import { z } from "zod"
4
+
5
+ /** Matches circuit-json's simulation_digital_stimulus pattern limit. */
6
+ const MAX_TRANSMITTED_BITS = 65536
7
+
8
+ /** Binary traffic for one external transient. Numeric times are milliseconds. */
9
+ export interface AnalogDigitalStimulusProps {
10
+ name: string
11
+ /** Selector for the external analog.transientsimulation experiment. */
12
+ simulationRef: string
13
+ /** Selector for the physical source pin driven by this stimulus. */
14
+ sourcePinRef: string
15
+ bitDuration: number | string
16
+ startTime: number | string
17
+ /** Initial bit before optional inversion. No traffic defaults are inferred. */
18
+ initialState: 0 | 1
19
+ inverted?: boolean
20
+ transmittedData: {
21
+ transmissionType: "bits"
22
+ bits: string | [0 | 1, ...(0 | 1)[]]
23
+ repeat: boolean
24
+ }
25
+ }
26
+ export const analogDigitalStimulusProps = z
27
+ .object({
28
+ name: z.string().min(1),
29
+ simulationRef: z.string().min(1),
30
+ sourcePinRef: z.string().min(1),
31
+ bitDuration: ms.refine(
32
+ (milliseconds) => Number.isFinite(milliseconds) && milliseconds > 0,
33
+ ),
34
+ startTime: ms.refine(
35
+ (milliseconds) => Number.isFinite(milliseconds) && milliseconds >= 0,
36
+ ),
37
+ initialState: z.union([z.literal(0), z.literal(1)]),
38
+ inverted: z.boolean().default(false),
39
+ transmittedData: z
40
+ .object({
41
+ transmissionType: z.literal("bits"),
42
+ bits: z.union([
43
+ z
44
+ .string()
45
+ .regex(/^[01]+$/)
46
+ .max(MAX_TRANSMITTED_BITS),
47
+ z
48
+ .array(z.union([z.literal(0), z.literal(1)]))
49
+ .nonempty()
50
+ .max(MAX_TRANSMITTED_BITS),
51
+ ]),
52
+ repeat: z.boolean(),
53
+ })
54
+ .strict(),
55
+ })
56
+ .strict()
57
+ expectTypesMatch<
58
+ AnalogDigitalStimulusProps,
59
+ z.input<typeof analogDigitalStimulusProps>
60
+ >(true)
@@ -0,0 +1,47 @@
1
+ import { ms } from "circuit-json"
2
+ import { expectTypesMatch } from "lib/typecheck"
3
+ import { z } from "zod"
4
+
5
+ /** Fixed-origin eye measurement. Numeric times are milliseconds; no compliance threshold is implied. */
6
+ export interface AnalogEyeDiagramProps {
7
+ name: string
8
+ simulationRef: string
9
+ probeRef: string
10
+ unitInterval: number | string
11
+ timeOrigin: number | string
12
+ /** Omitted gate endpoints use the experiment's recorded start/end times. */
13
+ startTime?: number | string
14
+ endTime?: number | string
15
+ }
16
+ const finiteMilliseconds = ms.refine(Number.isFinite)
17
+ export const analogEyeDiagramProps = z
18
+ .object({
19
+ name: z.string().min(1),
20
+ simulationRef: z.string().min(1),
21
+ probeRef: z.string().min(1),
22
+ unitInterval: finiteMilliseconds.refine((milliseconds) => milliseconds > 0),
23
+ timeOrigin: finiteMilliseconds,
24
+ startTime: finiteMilliseconds
25
+ .refine((milliseconds) => milliseconds >= 0)
26
+ .optional(),
27
+ endTime: finiteMilliseconds
28
+ .refine((milliseconds) => milliseconds > 0)
29
+ .optional(),
30
+ })
31
+ .strict()
32
+ .superRefine((eye, context) => {
33
+ if (
34
+ eye.startTime !== undefined &&
35
+ eye.endTime !== undefined &&
36
+ eye.startTime >= eye.endTime
37
+ ) {
38
+ context.addIssue({
39
+ code: z.ZodIssueCode.custom,
40
+ path: ["endTime"],
41
+ message: "Eye gate end must follow its start",
42
+ })
43
+ }
44
+ })
45
+ expectTypesMatch<AnalogEyeDiagramProps, z.input<typeof analogEyeDiagramProps>>(
46
+ true,
47
+ )
@@ -10,14 +10,14 @@ export interface AnalogSimulationProps {
10
10
  duration?: number | string
11
11
  startTime?: number | string
12
12
  timePerStep?: number | string
13
- spiceEngine?: AutocompleteString<"spicey" | "ngspice">
13
+ spiceEngine?: AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
14
14
  spiceOptions?: SpiceOptions
15
15
  graphIndependentAxes?: boolean
16
16
  }
17
17
 
18
- const spiceEngine = z.custom<AutocompleteString<"spicey" | "ngspice">>(
19
- (value) => typeof value === "string",
20
- )
18
+ const spiceEngine = z.custom<
19
+ AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
20
+ >((value) => typeof value === "string")
21
21
 
22
22
  export interface SpiceOptions {
23
23
  method?: "trap" | "gear"
@@ -37,7 +37,7 @@ export interface AnalogAnalysisSimulationBaseProps {
37
37
  /** Stable identity for the simulation experiment. */
38
38
  name?: string
39
39
  /** SPICE implementation used to run this analysis. */
40
- spiceEngine?: AutocompleteString<"spicey" | "ngspice">
40
+ spiceEngine?: AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
41
41
  /** Numerical solver settings forwarded to the selected SPICE engine. */
42
42
  spiceOptions?: SpiceOptions
43
43
  /** Render each probe with an independent vertical graph scale. */
@@ -1,6 +1,7 @@
1
1
  import { ms } from "circuit-json"
2
2
  import { expectTypesMatch } from "lib/typecheck"
3
3
  import { z } from "zod"
4
+ import { ibisPinRunState, type IbisPinRunState } from "lib/common/ibis"
4
5
  import {
5
6
  analogAnalysisSimulationBaseProps,
6
7
  type AnalogAnalysisSimulationBaseProps,
@@ -14,6 +15,8 @@ export interface AnalogTransientSimulationProps
14
15
  startTime?: number | string
15
16
  /** Maximum simulation timestep. Raw numbers are milliseconds. Defaults to 0.01ms. */
16
17
  timePerStep?: number | string
18
+ /** Physical pin selectors and per-experiment direction/enable states. Requires spiceEngine="pcb_spice"; rendering only declares the experiment. */
19
+ ibisPinStates?: Record<string, IbisPinRunState>
17
20
  }
18
21
 
19
22
  const positiveMilliseconds = ms.refine(
@@ -27,8 +30,16 @@ export const analogTransientSimulationProps = z
27
30
  duration: positiveMilliseconds.default("10ms"),
28
31
  startTime: ms.default("0ms"),
29
32
  timePerStep: positiveMilliseconds.default("0.01ms"),
33
+ ibisPinStates: z.record(z.string().min(1), ibisPinRunState).optional(),
30
34
  })
31
35
  .superRefine((simulation, context) => {
36
+ if (simulation.ibisPinStates && simulation.spiceEngine !== "pcb_spice") {
37
+ context.addIssue({
38
+ code: z.ZodIssueCode.custom,
39
+ path: ["ibisPinStates"],
40
+ message: "IBIS pin states require spiceEngine=pcb_spice",
41
+ })
42
+ }
32
43
  if (
33
44
  simulation.startTime < 0 ||
34
45
  simulation.startTime > simulation.duration
@@ -0,0 +1,13 @@
1
+ import { ibisModelDefinition, type IbisModelDefinition } from "lib/common/ibis"
2
+ import { expectTypesMatch } from "lib/typecheck"
3
+ import { z } from "zod"
4
+
5
+ /** Declares a model for an existing chip. Rendering never fetches or converts the source. */
6
+ export interface IbisModelProps extends IbisModelDefinition {
7
+ /** Selector for exactly one source component in this subcircuit. */
8
+ componentRef: string
9
+ }
10
+ export const ibisModelProps = ibisModelDefinition
11
+ .extend({ componentRef: z.string().min(1) })
12
+ .strict()
13
+ expectTypesMatch<IbisModelProps, z.input<typeof ibisModelProps>>(true)
@@ -12,6 +12,20 @@ export interface SymbolProps {
12
12
  originalFacingDirection?: "up" | "down" | "left" | "right"
13
13
  width?: string | number
14
14
  height?: string | number
15
+ /** CSS-style fill (default) and stretch resize axes independently; contain preserves proportions. */
16
+ fit?: "fill" | "contain" | "stretch"
17
+ /**
18
+ * Source sizing bounds in the local symbol coordinate space (mm, +X right, +Y up).
19
+ * With width/height, maps the bounds center to the symbol position; all artwork
20
+ * and ports use the same transform. Omitted uses automatic bounds including ports.
21
+ * maxX must exceed minX and maxY must exceed minY. No aliases; no change to existing defaults.
22
+ */
23
+ viewbox?: {
24
+ minX: number | string
25
+ maxX: number | string
26
+ minY: number | string
27
+ maxY: number | string
28
+ }
15
29
  name?: string
16
30
  }
17
31
 
@@ -22,6 +36,23 @@ export const symbolProps = z.object({
22
36
  .optional(),
23
37
  width: distance.optional(),
24
38
  height: distance.optional(),
39
+ fit: z.enum(["fill", "contain", "stretch"]).optional(),
40
+ viewbox: z
41
+ .object({
42
+ minX: distance,
43
+ maxX: distance,
44
+ minY: distance,
45
+ maxY: distance,
46
+ })
47
+ .refine((bounds) => bounds.maxX > bounds.minX, {
48
+ message: "viewbox maxX must exceed minX",
49
+ path: ["maxX"],
50
+ })
51
+ .refine((bounds) => bounds.maxY > bounds.minY, {
52
+ message: "viewbox maxY must exceed minY",
53
+ path: ["maxY"],
54
+ })
55
+ .optional(),
25
56
  name: z.string().optional(),
26
57
  })
27
58
 
package/lib/index.ts CHANGED
@@ -78,6 +78,10 @@ export * from "./components/push-button"
78
78
  export * from "./components/subcircuit"
79
79
  export * from "./components/analogsimulation"
80
80
  export * from "./components/analogtransientsimulation"
81
+ export * from "./common/ibis"
82
+ export * from "./components/ibismodel"
83
+ export * from "./components/analogdigitalstimulus"
84
+ export * from "./components/analogeyediagram"
81
85
  export * from "./components/analogdcoperatingpointsimulation"
82
86
  export * from "./components/analogdcsweepsimulation"
83
87
  export * from "./components/analogacsweepsimulation"
@@ -126,7 +126,7 @@ export interface PlatformConfig {
126
126
  includeBoardFiles?: string[]
127
127
  snapshotsDir?: string
128
128
 
129
- defaultSpiceEngine?: AutocompleteString<"spicey" | "ngspice">
129
+ defaultSpiceEngine?: AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
130
130
 
131
131
  unitPreference?: "mm" | "in" | "mil"
132
132
 
@@ -220,9 +220,9 @@ const spiceEngineZod = z.object({
220
220
  ),
221
221
  })
222
222
 
223
- const defaultSpiceEngine = z.custom<AutocompleteString<"spicey" | "ngspice">>(
224
- (value) => typeof value === "string",
225
- )
223
+ const defaultSpiceEngine = z.custom<
224
+ AutocompleteString<"spicey" | "ngspice" | "pcb_spice">
225
+ >((value) => typeof value === "string")
226
226
 
227
227
  const autorouterInstance = z.object({
228
228
  run: z
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/props",
3
- "version": "0.0.703",
3
+ "version": "0.0.705",
4
4
  "description": "Props for tscircuit builtin component types",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",