@tscircuit/schematic-viewer 2.0.55 → 2.0.57

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 (68) hide show
  1. package/dist/index.js +7 -3
  2. package/dist/index.js.map +1 -1
  3. package/package.json +4 -1
  4. package/.github/workflows/bun-formatcheck.yml +0 -26
  5. package/.github/workflows/bun-pver-release.yml +0 -59
  6. package/.github/workflows/bun-typecheck.yml +0 -26
  7. package/.github/workflows/on-merge-inform-release-tracker.yml +0 -24
  8. package/CLAUDE.md +0 -1
  9. package/biome.json +0 -56
  10. package/bun.lockb +0 -0
  11. package/cosmos.config.json +0 -3
  12. package/cosmos.decorator.tsx +0 -3
  13. package/docs/circuit-to-svg-metadata.md +0 -151
  14. package/docs/dragndrop-spec.md +0 -39
  15. package/examples/example1-resistor-and-capacitor.fixture.tsx +0 -16
  16. package/examples/example10-groups-view-schematic-groups.fixture.tsx +0 -76
  17. package/examples/example11-automatic-grouping-view-schematic-groups.fixture.tsx +0 -109
  18. package/examples/example12-spice-boost-converter.fixture.tsx +0 -78
  19. package/examples/example13-disablegroups.fixture.tsx +0 -30
  20. package/examples/example14-schematic-component-click.fixture.tsx +0 -46
  21. package/examples/example15-analog-simulation-viewer.fixture.tsx +0 -145
  22. package/examples/example16-no-analog-simulation.fixture.tsx +0 -13
  23. package/examples/example17-schematic-ports.fixture.tsx +0 -49
  24. package/examples/example2-small-circuit.fixture.tsx +0 -48
  25. package/examples/example3-small-circuit-without-debug-grid.fixture.tsx +0 -44
  26. package/examples/example4-reset-edit-events.fixture.tsx +0 -57
  27. package/examples/example5-circuit-json-rerender.fixture.tsx +0 -110
  28. package/examples/example6-click-to-interact.fixture.tsx +0 -36
  29. package/examples/example7-schematic-viewer-fix-snapping.fixture.tsx +0 -123
  30. package/examples/example8-color-overrides.fixture.tsx +0 -52
  31. package/examples/example9-spice-rc-charging-voltage-divider.fixture.tsx +0 -77
  32. package/index.html +0 -12
  33. package/lib/components/AnalogSimulationViewer.tsx +0 -300
  34. package/lib/components/ControlledSchematicViewer.tsx +0 -40
  35. package/lib/components/EditIcon.tsx +0 -46
  36. package/lib/components/GridIcon.tsx +0 -45
  37. package/lib/components/MouseTracker.tsx +0 -257
  38. package/lib/components/SchematicComponentMouseTarget.tsx +0 -189
  39. package/lib/components/SchematicPortMouseTarget.tsx +0 -224
  40. package/lib/components/SchematicViewer.tsx +0 -582
  41. package/lib/components/SpiceIcon.tsx +0 -14
  42. package/lib/components/SpicePlot.tsx +0 -221
  43. package/lib/components/SpiceSimulationIcon.tsx +0 -32
  44. package/lib/components/SpiceSimulationOverlay.tsx +0 -250
  45. package/lib/components/ViewMenu.tsx +0 -218
  46. package/lib/components/ViewMenuIcon.tsx +0 -47
  47. package/lib/dev/render-to-circuit-json.ts +0 -8
  48. package/lib/hooks/use-resize-handling.ts +0 -35
  49. package/lib/hooks/useChangeSchematicComponentLocationsInSvg.ts +0 -117
  50. package/lib/hooks/useChangeSchematicTracesForMovedComponents.ts +0 -121
  51. package/lib/hooks/useComponentDragging.ts +0 -251
  52. package/lib/hooks/useLocalStorage.ts +0 -63
  53. package/lib/hooks/useMouseEventsOverBoundingBox.ts +0 -74
  54. package/lib/hooks/useSchematicGroupsOverlay.ts +0 -364
  55. package/lib/hooks/useSpiceSimulation.ts +0 -149
  56. package/lib/index.ts +0 -4
  57. package/lib/types/edit-events.ts +0 -16
  58. package/lib/types/eecircuit-engine.d.ts +0 -147
  59. package/lib/utils/debug.ts +0 -9
  60. package/lib/utils/get-component-offset-due-to-events.ts +0 -43
  61. package/lib/utils/spice-utils.ts +0 -128
  62. package/lib/utils/z-index-map.ts +0 -11
  63. package/lib/workers/spice-simulation.worker.ts +0 -51
  64. package/scripts/build-worker-blob-url.ts +0 -55
  65. package/src/main.tsx +0 -21
  66. package/tsconfig.json +0 -33
  67. package/tsup-webworker.config.ts +0 -13
  68. package/vite.config.js +0 -15
@@ -1,147 +0,0 @@
1
- export declare type ComplexDataType = {
2
- name: string
3
-
4
- type: string
5
-
6
- values: ComplexNumber[]
7
- }
8
-
9
- export declare type ComplexNumber = {
10
- real: number
11
-
12
- img: number
13
- }
14
-
15
- /**
16
-
17
- * Read output from spice
18
-
19
- */
20
-
21
- export declare type RealDataType = {
22
- name: string
23
-
24
- type: string
25
-
26
- values: RealNumber[]
27
- }
28
-
29
- export declare type RealNumber = number
30
-
31
- export declare type ResultType =
32
- | {
33
- header: string
34
-
35
- numVariables: number
36
-
37
- variableNames: string[]
38
-
39
- numPoints: number
40
-
41
- dataType: "real"
42
-
43
- data: RealDataType[]
44
- }
45
- | {
46
- header: string
47
-
48
- numVariables: number
49
-
50
- variableNames: string[]
51
-
52
- numPoints: number
53
-
54
- dataType: "complex"
55
-
56
- data: ComplexDataType[]
57
- }
58
-
59
- export declare class Simulation {
60
- private pass
61
-
62
- private commandList
63
-
64
- private cmd
65
-
66
- private dataRaw
67
-
68
- private results
69
-
70
- private output
71
-
72
- private info
73
-
74
- private initInfo
75
-
76
- private error
77
-
78
- private initialized
79
-
80
- private netList
81
-
82
- private initPromiseResolve
83
-
84
- private runPromiseResolve
85
-
86
- private getInput
87
-
88
- /**
89
-
90
- * Internal startup method that sets up the Module and simulation loop.
91
-
92
- */
93
-
94
- private startInternal
95
-
96
- /**
97
-
98
- * Public start method.
99
-
100
- * Returns a promise that resolves when the simulation module is initialized.
101
-
102
- */
103
-
104
- start: () => Promise<void>
105
-
106
- /**
107
-
108
- * Triggers a simulation run and returns a promise that resolves with the results.
109
-
110
- */
111
-
112
- runSim: () => Promise<ResultType>
113
-
114
- /**
115
-
116
- * Waits for a new simulation trigger.
117
-
118
- */
119
-
120
- private waitForNextRun
121
-
122
- /**
123
-
124
- * Resolves the waiting promise to continue the simulation loop.
125
-
126
- */
127
-
128
- private continueRun
129
-
130
- private outputEvent
131
-
132
- setNetList: (input: string) => void
133
-
134
- private setOutputEvent
135
-
136
- getInfo: () => string
137
-
138
- getInitInfo: () => string
139
-
140
- getError: () => string[]
141
-
142
- isInitialized: () => boolean
143
-
144
- private log_debug
145
- }
146
-
147
- export {}
@@ -1,9 +0,0 @@
1
- import Debug from "debug"
2
-
3
- export const debug = Debug("schematic-viewer")
4
-
5
- export const enableDebug = () => {
6
- Debug.enable("schematic-viewer*")
7
- }
8
-
9
- export default debug
@@ -1,43 +0,0 @@
1
- import type {
2
- EditSchematicComponentLocationEvent,
3
- EditSchematicComponentLocationEventWithElement,
4
- ManualEditEvent,
5
- } from "lib/types/edit-events"
6
-
7
- /**
8
- * Returns the total offset of a component due to a set of edit events in
9
- * mm
10
- */
11
- export const getComponentOffsetDueToEvents = ({
12
- editEvents,
13
- schematic_component_id,
14
- }: {
15
- editEvents: ManualEditEvent[]
16
- schematic_component_id: string
17
- }) => {
18
- const editEventsForComponent: EditSchematicComponentLocationEvent[] =
19
- editEvents
20
- .filter(
21
- (event) =>
22
- "schematic_component_id" in event &&
23
- event.schematic_component_id === schematic_component_id,
24
- )
25
- .filter(
26
- (event) =>
27
- "edit_event_type" in event &&
28
- event.edit_event_type === "edit_schematic_component_location",
29
- )
30
-
31
- const totalOffsetX = editEventsForComponent.reduce((acc, event) => {
32
- return acc + event.new_center.x - event.original_center.x
33
- }, 0)
34
-
35
- const totalOffsetY = editEventsForComponent.reduce((acc, event) => {
36
- return acc + event.new_center.y - event.original_center.y
37
- }, 0)
38
-
39
- return {
40
- x: totalOffsetX,
41
- y: totalOffsetY,
42
- }
43
- }
@@ -1,128 +0,0 @@
1
- import { circuitJsonToSpice } from "circuit-json-to-spice"
2
- import type { CircuitJson } from "circuit-json"
3
-
4
- export interface SpiceSimOptions {
5
- showVoltage: boolean
6
- showCurrent: boolean
7
- startTime: number // in ms
8
- duration: number // in ms
9
- }
10
-
11
- const formatSimTime = (seconds: number): string => {
12
- if (seconds === 0) return "0"
13
- const absSeconds = Math.abs(seconds)
14
-
15
- const precision = (v: number) => v.toPrecision(4)
16
-
17
- if (absSeconds >= 1) return precision(seconds)
18
- if (absSeconds >= 1e-3) return `${precision(seconds * 1e3)}m`
19
- if (absSeconds >= 1e-6) return `${precision(seconds * 1e6)}u`
20
- if (absSeconds >= 1e-9) return `${precision(seconds * 1e9)}n`
21
- if (absSeconds >= 1e-12) return `${precision(seconds * 1e12)}p`
22
- if (absSeconds >= 1e-15) return `${precision(seconds * 1e15)}f`
23
-
24
- return seconds.toExponential(3)
25
- }
26
-
27
- export const getSpiceFromCircuitJson = (
28
- circuitJson: CircuitJson,
29
- options?: Partial<SpiceSimOptions>,
30
- ): string => {
31
- const spiceNetlist = circuitJsonToSpice(circuitJson as any)
32
- const baseSpiceString = spiceNetlist.toSpiceString()
33
-
34
- const lines = baseSpiceString.split("\n").filter((l) => l.trim() !== "")
35
- const componentLines = lines.filter(
36
- (l) => !l.startsWith("*") && !l.startsWith(".") && l.trim() !== "",
37
- )
38
-
39
- const allNodes = new Set<string>()
40
- const capacitorNodes = new Set<string>()
41
- const componentNamesToProbeCurrent = new Set<string>()
42
-
43
- for (const line of componentLines) {
44
- const parts = line.trim().split(/\s+/)
45
- if (parts.length < 3) continue
46
-
47
- const componentName = parts[0]
48
- const componentType = componentName[0].toUpperCase()
49
- let nodesOnLine: string[] = []
50
-
51
- if (["R", "C", "L", "V", "I", "D"].includes(componentType)) {
52
- nodesOnLine = parts.slice(1, 3)
53
- // Only probe current on voltage sources
54
- if (componentType === "V") {
55
- componentNamesToProbeCurrent.add(componentName)
56
- }
57
- } else if (componentType === "Q" && parts.length >= 4) {
58
- // BJT
59
- nodesOnLine = parts.slice(1, 4)
60
- } else if (componentType === "M" && parts.length >= 5) {
61
- // MOSFET
62
- nodesOnLine = parts.slice(1, 5)
63
- } else if (componentType === "X") {
64
- // Subcircuit
65
- // Assume last part is model name, everything in between is a node
66
- nodesOnLine = parts.slice(1, -1)
67
- } else {
68
- continue
69
- }
70
-
71
- nodesOnLine.forEach((node) => allNodes.add(node))
72
-
73
- if (componentType === "C") {
74
- nodesOnLine.forEach((node) => capacitorNodes.add(node))
75
- }
76
- }
77
-
78
- // Do not probe/set IC for ground
79
- allNodes.delete("0")
80
- capacitorNodes.delete("0")
81
-
82
- const icLines = Array.from(capacitorNodes).map((node) => `.ic V(${node})=0`)
83
-
84
- const probes: string[] = []
85
- const probeVoltages = Array.from(allNodes).map((node) => `V(${node})`)
86
- probes.push(...probeVoltages)
87
- const probeCurrents = Array.from(componentNamesToProbeCurrent).map(
88
- (name) => `I(${name})`,
89
- )
90
- probes.push(...probeCurrents)
91
-
92
- const probeLine = probes.length > 0 ? `.probe ${probes.join(" ")}` : ""
93
-
94
- const tstart_ms = options?.startTime ?? 0
95
- const duration_ms = options?.duration ?? 20
96
- const tstart = tstart_ms * 1e-3 // s
97
- const duration = duration_ms * 1e-3 // s
98
-
99
- const tstop = tstart + duration
100
- const tstep = duration / 50
101
- const tranLine = `.tran ${formatSimTime(tstep)} ${formatSimTime(
102
- tstop,
103
- )} ${formatSimTime(tstart)} UIC`
104
-
105
- const endStatement = ".end"
106
- const originalLines = baseSpiceString.split("\n")
107
- let endIndex = -1
108
- for (let i = originalLines.length - 1; i >= 0; i--) {
109
- if (originalLines[i].trim().toLowerCase().startsWith(endStatement)) {
110
- endIndex = i
111
- break
112
- }
113
- }
114
-
115
- const injectionLines = [...icLines, probeLine, tranLine].filter(Boolean)
116
-
117
- let finalLines: string[]
118
-
119
- if (endIndex !== -1) {
120
- const beforeEnd = originalLines.slice(0, endIndex)
121
- const endLineAndAfter = originalLines.slice(endIndex)
122
- finalLines = [...beforeEnd, ...injectionLines, ...endLineAndAfter]
123
- } else {
124
- finalLines = [...originalLines, ...injectionLines, endStatement]
125
- }
126
-
127
- return finalLines.join("\n")
128
- }
@@ -1,11 +0,0 @@
1
- export const zIndexMap = {
2
- schematicEditIcon: 50,
3
- schematicGridIcon: 49,
4
- spiceSimulationIcon: 50,
5
- viewMenuIcon: 48,
6
- viewMenu: 55,
7
- viewMenuBackdrop: 54,
8
- clickToInteractOverlay: 100,
9
- schematicComponentHoverOutline: 47,
10
- schematicPortHoverOutline: 48,
11
- }
@@ -1,51 +0,0 @@
1
- import type * as EecircuitEngine from "../types/eecircuit-engine"
2
-
3
- let sim: EecircuitEngine.Simulation | null = null
4
-
5
- const fetchSimulation = async (): Promise<
6
- typeof EecircuitEngine.Simulation
7
- > => {
8
- const module = await import(
9
- // @ts-ignore
10
- "https://cdn.jsdelivr.net/npm/eecircuit-engine@1.5.2/+esm"
11
- )
12
- return module.Simulation as typeof EecircuitEngine.Simulation
13
- }
14
-
15
- const initializeSimulation = async () => {
16
- if (sim && sim.isInitialized()) return
17
- const Simulation = await fetchSimulation()
18
- sim = new Simulation()
19
- await sim.start()
20
- }
21
-
22
- self.onmessage = async (event: MessageEvent<{ spiceString: string }>) => {
23
- try {
24
- await initializeSimulation()
25
- if (!sim) throw new Error("Simulation not initialized")
26
-
27
- let engineSpiceString = event.data.spiceString
28
- const wrdataMatch = engineSpiceString.match(/wrdata\s+(\S+)\s+(.*)/i)
29
- if (wrdataMatch) {
30
- const variables = wrdataMatch[2].trim().split(/\s+/)
31
- const probeLine = `.probe ${variables.join(" ")}`
32
- engineSpiceString = engineSpiceString.replace(/wrdata.*/i, probeLine)
33
- } else if (!engineSpiceString.match(/\.probe/i)) {
34
- const plotMatch = engineSpiceString.match(/plot\s+(.*)/i)
35
- if (plotMatch) {
36
- throw new Error(
37
- "The 'plot' command is not supported for data extraction. Please use 'wrdata <filename> <var1> ...' or '.probe <var1> ...' instead.",
38
- )
39
- }
40
- throw new Error(
41
- "No '.probe' or 'wrdata' command found in SPICE file. Use 'wrdata <filename> <var1> ...' to specify output.",
42
- )
43
- }
44
-
45
- sim.setNetList(engineSpiceString)
46
- const result = await sim.runSim()
47
- self.postMessage({ type: "result", result })
48
- } catch (e: any) {
49
- self.postMessage({ type: "error", error: e.message })
50
- }
51
- }
@@ -1,55 +0,0 @@
1
- import fs from "fs/promises"
2
- import path from "path"
3
-
4
- const workerInputPath = path.resolve(
5
- process.cwd(),
6
- "dist/workers/spice-simulation.worker.js",
7
- )
8
- const workerOutputPath = path.resolve(
9
- process.cwd(),
10
- "lib/workers/spice-simulation.worker.blob.js",
11
- )
12
-
13
- const build = async () => {
14
- try {
15
- await fs.mkdir(path.dirname(workerOutputPath), { recursive: true })
16
- const workerCode = await fs.readFile(workerInputPath, "utf-8")
17
-
18
- const base64 = Buffer.from(workerCode).toString("base64")
19
-
20
- const blobUrlModule = `// This file is generated by scripts/build-worker-blob-url.ts
21
- // Do not edit this file directly.
22
-
23
- const b64 = "${base64}";
24
-
25
- let blobUrl = null;
26
-
27
- export const getSpiceSimulationWorkerBlobUrl = () => {
28
- if (typeof window === "undefined") return null;
29
- if (blobUrl) return blobUrl;
30
-
31
- try {
32
- const blob = new Blob([atob(b64)], { type: "application/javascript" });
33
- blobUrl = URL.createObjectURL(blob);
34
- return blobUrl;
35
- } catch (e) {
36
- console.error("Failed to create blob URL for worker", e);
37
- return null;
38
- }
39
- };
40
- `
41
-
42
- await fs.writeFile(workerOutputPath, blobUrlModule)
43
- console.log(`Wrote worker blob URL module to ${workerOutputPath}`)
44
- } catch (e: any) {
45
- if (e.code === "ENOENT") {
46
- console.error(`Error: Worker file not found at ${workerInputPath}`)
47
- console.error("Please run 'bun run build:webworker' first.")
48
- } else {
49
- console.error("Failed to build worker blob URL", e)
50
- }
51
- process.exit(1)
52
- }
53
- }
54
-
55
- build()
package/src/main.tsx DELETED
@@ -1,21 +0,0 @@
1
- import React from "react"
2
- import { createRoot } from "react-dom/client"
3
- import { renderToCircuitJson } from "lib/dev/render-to-circuit-json"
4
- import { SchematicViewer } from "lib/components/SchematicViewer"
5
-
6
- const root = createRoot(document.getElementById("root")!)
7
-
8
- root.render(
9
- <React.StrictMode>
10
- <div style={{ width: "100vw", height: "100vh" }}>
11
- <SchematicViewer
12
- circuitJson={renderToCircuitJson(
13
- <board width="10mm" height="10mm">
14
- <resistor name="R1" resistance={1000} />
15
- </board>,
16
- )}
17
- containerStyle={{ height: "100%" }}
18
- />
19
- </div>
20
- </React.StrictMode>,
21
- )
package/tsconfig.json DELETED
@@ -1,33 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- // Enable latest features
4
- "lib": ["ESNext", "DOM"],
5
- "target": "ES2020",
6
- "module": "ESNext",
7
- "moduleDetection": "force",
8
- "jsx": "react-jsx",
9
- "allowJs": true,
10
-
11
- "baseUrl": ".",
12
- "paths": {
13
- "lib/*": ["lib/*"]
14
- },
15
- "esModuleInterop": true,
16
-
17
- // Bundler mode
18
- "moduleResolution": "bundler",
19
- "allowImportingTsExtensions": true,
20
- "verbatimModuleSyntax": true,
21
- "noEmit": true,
22
-
23
- // Best practices
24
- "strict": true,
25
- "skipLibCheck": true,
26
- "noFallthroughCasesInSwitch": true,
27
-
28
- // Some stricter flags (disabled by default)
29
- "noUnusedLocals": false,
30
- "noUnusedParameters": false,
31
- "noPropertyAccessFromIndexSignature": false
32
- }
33
- }
@@ -1,13 +0,0 @@
1
- import { defineConfig } from "tsup"
2
-
3
- export default defineConfig({
4
- entry: ["lib/workers/spice-simulation.worker.ts"],
5
- outDir: "dist/workers",
6
- format: ["esm"],
7
- platform: "browser",
8
- dts: false,
9
- splitting: false,
10
- sourcemap: false,
11
- clean: true,
12
- minify: true,
13
- })
package/vite.config.js DELETED
@@ -1,15 +0,0 @@
1
- import { defineConfig } from "vite"
2
- import react from "@vitejs/plugin-react"
3
- import { resolve } from "node:path"
4
-
5
- export default defineConfig({
6
- plugins: [react()],
7
- resolve: {
8
- alias: {
9
- lib: resolve(__dirname, "./lib"),
10
- },
11
- },
12
- define: {
13
- global: {},
14
- },
15
- })