circuitjson-toolkit 1.0.17 → 1.1.1

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 (155) hide show
  1. package/NOTICE.md +31 -0
  2. package/README.md +274 -107
  3. package/docs/api.md +507 -96
  4. package/docs/capabilities.md +70 -0
  5. package/docs/migration/behaviors.md +45 -0
  6. package/docs/migration/parser.md +60 -0
  7. package/docs/migration/renderers.md +515 -0
  8. package/docs/migration/root.md +740 -0
  9. package/docs/migration.md +126 -0
  10. package/docs/model-format.md +175 -57
  11. package/docs/provenance.md +206 -0
  12. package/docs/release-notes-v1.1.0.md +154 -0
  13. package/docs/release-notes-v1.1.1.md +24 -0
  14. package/docs/testing.md +122 -7
  15. package/package.json +32 -5
  16. package/spec/api-baseline-v1.0.17.json +1 -0
  17. package/spec/baseline-provenance-v1.0.17.json +7 -0
  18. package/spec/circuitjson-schema-snapshot.json +321 -0
  19. package/spec/circuitjson-schema-source.json +28 -0
  20. package/spec/feature-preservation.json +1 -0
  21. package/spec/library-scope.md +27 -20
  22. package/src/capabilities.mjs +1 -0
  23. package/src/core/ArchiveEntryPath.mjs +93 -0
  24. package/src/core/ArchiveLimits.mjs +31 -0
  25. package/src/core/ArchiveLimitsValidator.mjs +107 -0
  26. package/src/core/AsyncInputOwnership.mjs +56 -0
  27. package/src/core/AttachedValueLimits.mjs +67 -0
  28. package/src/core/CircuitJsonDiagnosticIndexer.mjs +184 -0
  29. package/src/core/CircuitJsonDocument.mjs +19 -61
  30. package/src/core/CircuitJsonElementTypes.mjs +10 -0
  31. package/src/core/CircuitJsonElementValidator.mjs +98 -847
  32. package/src/core/CircuitJsonIndexer.mjs +274 -194
  33. package/src/core/CircuitJsonManufacturingBuilder.mjs +167 -164
  34. package/src/core/CircuitJsonParser.mjs +75 -13
  35. package/src/core/CircuitJsonPcbClearanceDiagnostics.mjs +12 -6
  36. package/src/core/CircuitJsonPcbHolePrimitiveModel.mjs +108 -10
  37. package/src/core/CircuitJsonPcbPadPrimitiveModel.mjs +1 -1
  38. package/src/core/CircuitJsonPcbPrimitiveArtwork.mjs +44 -38
  39. package/src/core/CircuitJsonPcbPrimitiveBuilder.mjs +146 -28
  40. package/src/core/CircuitJsonPcbPrimitiveFields.mjs +70 -4
  41. package/src/core/CircuitJsonPcbPrimitiveIndex.mjs +18 -2
  42. package/src/core/CircuitJsonPcbPrimitiveOverlays.mjs +26 -9
  43. package/src/core/CircuitJsonPcbZonePrimitiveBuilder.mjs +7 -6
  44. package/src/core/CircuitJsonSerializedInputAudit.mjs +87 -0
  45. package/src/core/CircuitJsonSourceMetadata.mjs +5 -1
  46. package/src/core/CircuitJsonSupportMatrixBuilder.mjs +3 -1
  47. package/src/core/CircuitJsonToolkitElementSchema.mjs +218 -0
  48. package/src/core/CircuitJsonUnitParsers.mjs +101 -0
  49. package/src/core/CircuitJsonUnits.mjs +13 -87
  50. package/src/core/CircuitJsonUpstreamSchema.mjs +9 -0
  51. package/src/core/CircuitJsonUpstreamValidator.mjs +418 -0
  52. package/src/core/CircuitJsonValidationUnits.mjs +6 -0
  53. package/src/core/ManufacturingService.mjs +323 -0
  54. package/src/core/Parser.mjs +343 -0
  55. package/src/core/ParserOptions.mjs +333 -0
  56. package/src/core/PcbBoundsSelectionModel.mjs +55 -19
  57. package/src/core/PcbDiagnosticFocusModel.mjs +42 -11
  58. package/src/core/PcbInteractionIndex.mjs +368 -0
  59. package/src/core/PcbInteractionPrimitiveModel.mjs +393 -62
  60. package/src/core/ProjectAsyncInputOwner.mjs +70 -0
  61. package/src/core/ProjectLoader.mjs +975 -0
  62. package/src/core/SimulationService.mjs +790 -0
  63. package/src/core/ToolkitCapabilities.mjs +130 -0
  64. package/src/core/ZipArchiveInspector.mjs +649 -0
  65. package/src/core/context/BinaryDataSnapshot.mjs +217 -0
  66. package/src/core/context/CircuitJsonContextIndexes.mjs +96 -0
  67. package/src/core/context/CircuitJsonDerivedCache.mjs +114 -0
  68. package/src/core/context/CircuitJsonDocumentContext.mjs +353 -0
  69. package/src/core/context/CircuitJsonLegacyModel.mjs +147 -0
  70. package/src/core/context/CircuitJsonLegacyNormalizer.mjs +847 -0
  71. package/src/core/context/CircuitJsonMetadataBoundary.mjs +76 -0
  72. package/src/core/context/CircuitJsonModelFreezeTraversal.mjs +179 -0
  73. package/src/core/context/CircuitJsonReadOnlyDocument.mjs +920 -0
  74. package/src/core/context/CircuitJsonSchematicTableNormalizer.mjs +314 -0
  75. package/src/core/context/CircuitJsonValidationAuthority.mjs +39 -0
  76. package/src/core/context/CircuitJsonValidationProof.mjs +217 -0
  77. package/src/core/context/PcbPrimitivePreparation.mjs +198 -0
  78. package/src/core/context/PcbSpatialIndex.mjs +701 -0
  79. package/src/core/context/ProtectedExtensionBinaryBoundary.mjs +128 -0
  80. package/src/core/context/StructuredDataSnapshot.mjs +683 -0
  81. package/src/core/contracts/DocumentResult.mjs +198 -0
  82. package/src/core/contracts/ProjectResult.mjs +96 -0
  83. package/src/core/contracts/RuntimeProxyBoundary.mjs +48 -0
  84. package/src/core/contracts/ToolkitAsset.mjs +493 -0
  85. package/src/core/contracts/ToolkitDiagnostic.mjs +38 -0
  86. package/src/core/contracts/ToolkitError.mjs +176 -0
  87. package/src/core/contracts/ToolkitProgress.mjs +89 -0
  88. package/src/core/interaction/CanonicalInteractionOptions.mjs +246 -0
  89. package/src/core/interaction/PcbInteractionBounds.mjs +167 -0
  90. package/src/core/query/CircuitTraversal.mjs +343 -0
  91. package/src/core/query/ComponentGrouping.mjs +275 -0
  92. package/src/core/query/QueryNetlistBuilder.mjs +306 -0
  93. package/src/core/query/QueryService.mjs +435 -0
  94. package/src/core/query/RegexPattern.mjs +75 -0
  95. package/src/core/rendering/CanonicalBomOrder.mjs +81 -0
  96. package/src/core/rendering/CanonicalBomRows.mjs +92 -0
  97. package/src/core/rendering/CanonicalRenderOptions.mjs +498 -0
  98. package/src/core/rendering/CanonicalSvgDocument.mjs +102 -0
  99. package/src/core/rendering/PcbRenderPlan.mjs +429 -0
  100. package/src/core/rendering/SchematicSheetSelector.mjs +335 -0
  101. package/src/core/scene3d/PcbScene3dBuilder.mjs +906 -0
  102. package/src/core/scene3d/PcbScene3dPreparator.mjs +47 -0
  103. package/src/core/scene3d/Scene3dAssetIndex.mjs +284 -0
  104. package/src/core/scene3d/Scene3dBoardModel.mjs +596 -0
  105. package/src/core/scene3d/Scene3dDocumentMetadata.mjs +167 -0
  106. package/src/core/scene3d/Scene3dFreeze.mjs +37 -0
  107. package/src/core/scene3d/Scene3dIdRegistry.mjs +34 -0
  108. package/src/core/scene3d/Scene3dInputPreflight.mjs +193 -0
  109. package/src/core/scene3d/Scene3dMaterials.mjs +58 -0
  110. package/src/core/scene3d/Scene3dModelReference.mjs +134 -0
  111. package/src/core/scene3d/Scene3dOptions.mjs +363 -0
  112. package/src/core/scene3d/SceneAssetResolver.mjs +441 -0
  113. package/src/core/simulation/SimulationParameterCloner.mjs +543 -0
  114. package/src/core/worker/ParserWorkerClient.mjs +999 -0
  115. package/src/core/worker/ToolkitWorkerProtocol.mjs +412 -0
  116. package/src/core/worker/WorkerRequestData.mjs +650 -0
  117. package/src/core/worker/WorkerResponseData.mjs +905 -0
  118. package/src/extensions.mjs +37 -0
  119. package/src/index.mjs +14 -9
  120. package/src/interaction.mjs +2 -0
  121. package/src/manufacturing.mjs +1 -0
  122. package/src/parser.mjs +12 -2
  123. package/src/project.mjs +5 -0
  124. package/src/query.mjs +1 -0
  125. package/src/renderers.mjs +3 -29
  126. package/src/scene3d.mjs +3 -0
  127. package/src/simulation.mjs +1 -0
  128. package/src/styles/renderers.css +24 -0
  129. package/src/testing/ToolkitContractFixtures.mjs +124 -0
  130. package/src/testing/ToolkitLoopbackWorker.mjs +174 -0
  131. package/src/testing/runToolkitContract.mjs +705 -0
  132. package/src/testing.mjs +3 -0
  133. package/src/ui/BomTableRenderer.mjs +304 -0
  134. package/src/ui/CircuitJsonPcbBoardSvgRenderer.mjs +80 -0
  135. package/src/ui/CircuitJsonPcbPrimitiveAttributeRenderer.mjs +3 -5
  136. package/src/ui/CircuitJsonPcbSvgRenderer.mjs +63 -43
  137. package/src/ui/CircuitJsonPcbViaSvgRenderer.mjs +3 -5
  138. package/src/ui/CircuitJsonSchematicDebugRenderer.mjs +164 -0
  139. package/src/ui/CircuitJsonSchematicImageSvgRenderer.mjs +210 -0
  140. package/src/ui/CircuitJsonSchematicLineRenderer.mjs +86 -0
  141. package/src/ui/CircuitJsonSchematicSheetSymbolSvgRenderer.mjs +98 -0
  142. package/src/ui/CircuitJsonSchematicSvgArcPath.mjs +117 -17
  143. package/src/ui/CircuitJsonSchematicSvgPortMetadata.mjs +67 -20
  144. package/src/ui/CircuitJsonSchematicSvgPrimitiveAttributes.mjs +45 -9
  145. package/src/ui/CircuitJsonSchematicSvgRenderer.mjs +151 -148
  146. package/src/ui/CircuitJsonSchematicTableSvgRenderer.mjs +4 -292
  147. package/src/ui/PcbSvgRenderer.mjs +41 -0
  148. package/src/ui/SafeSvgPaint.mjs +26 -0
  149. package/src/ui/SafeXmlText.mjs +60 -0
  150. package/src/ui/SchematicGeometryBounds.mjs +540 -0
  151. package/src/ui/SchematicSvgRenderer.mjs +110 -0
  152. package/src/ui/SchematicTableGeometry.mjs +319 -0
  153. package/src/ui/SchematicTextAnchor.mjs +55 -0
  154. package/src/ui/SchematicTextBounds.mjs +98 -0
  155. package/src/workers/parser.worker.mjs +59 -0
package/NOTICE.md CHANGED
@@ -28,3 +28,34 @@ For applications with an "About", "Licenses", or "Legal Notices" screen,
28
28
  include a reasonable reference to this project and its original author there.
29
29
 
30
30
  Package-manager dependencies retain their own licenses.
31
+
32
+ ## Canonical ECAD toolkit convergence
33
+
34
+ Version 1.1.0 defines the common parser, project, renderer, interaction, query,
35
+ manufacturing, simulation, data-only 3D scene, capability, error, and worker
36
+ contracts used by CircuitJSON Toolkit, Gerber Toolkit, Altium Toolkit, and
37
+ KiCad Toolkit.
38
+
39
+ Source-format packages retain their own native decoders, fidelity engines,
40
+ assets, reports, and license terms. Shared behavior generalized here operates
41
+ on standards-only CircuitJSON and does not copy source-format parser models or
42
+ renderer graphs. `docs/provenance.md` records consulted behavior and adapted
43
+ ownership boundaries.
44
+
45
+ The `circuit-json` schema package is used only for development-time schema
46
+ verification. It is not a runtime dependency or bundled production edge.
47
+
48
+ ## Query behavior references
49
+
50
+ The shared CircuitJSON query contract was independently implemented after
51
+ reviewing the byte-identical netlist-query behavior in these projects:
52
+
53
+ - Altium Toolkit (`https://github.com/SunboX/altium-toolkit`), source commit
54
+ `e8a8cd551ad103cd0cf96bb5b5f5b816874ed72b`;
55
+ - KiCad Toolkit (`https://github.com/SunboX/kicad-toolkit`), source commit
56
+ `02e38fe0b961a09d2ff25462b9b00207326743d2`.
57
+
58
+ Those consulted files are Copyright (C) 2026 André Fiedler and licensed
59
+ `GPL-3.0-or-later`. CircuitJSON Toolkit does not copy their source text or
60
+ package-native model logic; `docs/provenance.md` records the per-module
61
+ behavior-only reuse decisions.
package/README.md CHANGED
@@ -6,169 +6,328 @@ SPDX-License-Identifier: CC-BY-SA-4.0
6
6
 
7
7
  # CircuitJSON Toolkit
8
8
 
9
- CircuitJSON Toolkit is an ESM JavaScript library for parsing, validating,
10
- indexing, and inspecting serialized CircuitJSON element arrays.
9
+ CircuitJSON Toolkit is the dependency-free common runtime for the ECAD toolkit
10
+ family. It provides the same parser, project, rendering, interaction, query,
11
+ manufacturing, simulation, 3D scene, capability, error, and worker contracts
12
+ used by `gerber-toolkit`, `altium-toolkit`, and `kicad-toolkit`.
13
+
14
+ CircuitJSON is the shared immutable model. Source-format packages keep their
15
+ native decoders and fidelity data in explicit extension namespaces while
16
+ common services operate on `DocumentResult.model` or a reused
17
+ `CircuitJsonDocumentContext`.
18
+
19
+ The package is browser- and Node-compatible, local-first, and has no runtime
20
+ dependencies. It does not import Three.js, the DOM, filesystem APIs, or network
21
+ clients.
22
+
23
+ ## Breaking API convergence
24
+
25
+ Version 1.1.0 intentionally changes names, parameters, return shapes, and
26
+ package subpaths to match the Gerber, Altium, and KiCad toolkits. The root is an
27
+ exact 17-class surface: 14 common classes plus three deprecated viewer
28
+ compatibility classes. Previous CircuitJSON-specific utilities were not
29
+ deleted: 37 source-neutral compatibility exports moved to
30
+ `circuitjson-toolkit/extensions`.
31
+
32
+ See the [migration guide](docs/migration.md) and its generated
33
+ [root](docs/migration/root.md), [parser](docs/migration/parser.md),
34
+ [renderer](docs/migration/renderers.md), and
35
+ [behavior](docs/migration/behaviors.md) appendices for all 1,207 preserved
36
+ 1.0.17 features. The
37
+ [1.1.0 release notes](docs/release-notes-v1.1.0.md) provide the concise change
38
+ summary.
39
+
40
+ Version 1.1.1 makes queued worker-request ownership synchronous. Parser and
41
+ project requests waiting behind active work can no longer observe later
42
+ caller-buffer mutation; explicit transfers detach exact buffers immediately
43
+ after admission. See the
44
+ [1.1.1 release notes](docs/release-notes-v1.1.1.md).
45
+
46
+ Before 1.1.0:
11
47
 
12
- The package was extracted from [ECAD Forge](https://ecadforge.app/), where it
13
- is used as the shared CircuitJSON runtime utility layer between ECAD parsers,
14
- viewer adapters, and browser-based import flows. Its parser-style API,
15
- metadata conventions, and local-first behavior are designed to line up with
16
- packages such as `altium-toolkit` and `kicad-toolkit`, while remaining
17
- independent of any source ECAD format.
48
+ ```js
49
+ import { CircuitJsonParser } from 'circuitjson-toolkit'
18
50
 
19
- This package is intentionally separate from
20
- [`pcb-scene3d-viewer`](https://www.npmjs.com/package/pcb-scene3d-viewer).
21
- `circuitjson-toolkit` owns CircuitJSON parsing, validation, indexing, and unit
22
- helpers. `pcb-scene3d-viewer` owns Three.js runtime rendering and consumes this
23
- package as a normal npm dependency.
51
+ const model = CircuitJsonParser.parseText(text, {
52
+ fileName: 'board.json'
53
+ })
54
+ ```
55
+
56
+ After 1.1.0:
57
+
58
+ ```js
59
+ import { Parser } from 'circuitjson-toolkit'
60
+
61
+ const document = Parser.parse({
62
+ fileName: 'board.json',
63
+ data: text
64
+ })
65
+ const model = document.model
66
+ ```
24
67
 
25
68
  ## Features
26
69
 
27
- - Parse standalone CircuitJSON `.json` text from strings, `ArrayBuffer`, or
28
- `Uint8Array` input
29
- - Validate serialized CircuitJSON element arrays with a small, stable document
30
- API
31
- - Attach parser-style metadata such as `fileName`, `fileType`, `kind`, and
32
- `sourceFormat`, matching the conventions used by the ECAD toolkit packages
33
- - Build lookup indexes by element type and stable CircuitJSON identifiers
34
- - Resolve source component and PCB component maps for viewer, QA, export, or
35
- reporting integrations
36
- - Reject unknown element types and invalid core element fields before consumers
37
- render or query the model
38
- - Convert CircuitJSON millimeter dimensions and points into mils for render
39
- adapters that use PCB imperial units internally
40
- - Run dependency-free SPICE transient examples or normalize injected simulator
41
- results into complete CircuitJSON simulation experiment element sets
42
- - Provide root and parser-focused ESM entrypoints
43
- - Run in browser and Node ESM environments
44
- - Run entirely with local input data; no network calls are made by the parser
45
- - Stay dependency-free at runtime
70
+ - Exact `Parser` and `ProjectLoader` contracts with typed envelopes and errors
71
+ - Immutable CircuitJSON validation proofs and request-scoped reusable indexes
72
+ - Copy-on-write normalization of supported legacy CircuitJSON aliases through
73
+ `CircuitJsonDocument.normalizeModel()`
74
+ - Deterministic PCB, schematic, and BOM renderers
75
+ - Asset-backed `schematic_image` rows and hierarchical
76
+ `schematic_sheet_symbol` rows with shared bounds and SVG behavior
77
+ - Reusable exact PCB interaction and spatial indexes
78
+ - Query, manufacturing, and injected simulation services
79
+ - Data-only, millimeter-based, right-handed Z-up PCB 3D scenes
80
+ - Descriptor-safe `ToolkitAsset` measurement and preparation with zero-copy
81
+ metadata mode, one-copy full mode, and shared ECAD model/image media-type
82
+ inference
83
+ - Explicit asynchronous scene-asset preparation without implicit I/O
84
+ - Strict `ecad-toolkit.worker.v1` parsing/project protocol with progress,
85
+ cancellation, and controlled buffer transfer
86
+ - One-pass ownership for selected source extensions, with a separate 128 MiB /
87
+ 2,000,000-item bound and exact direct/worker result parity
88
+ - Machine-readable capability inventory and packed downstream conformance
89
+ harness
90
+ - Explicit `/extensions` surface retaining every previous specialized API
91
+ - Local-only behavior and no runtime package dependencies
46
92
 
47
93
  ## Install
48
94
 
49
- The package is published on npm as
50
- [`circuitjson-toolkit`](https://www.npmjs.com/package/circuitjson-toolkit).
51
-
52
95
  ```bash
53
96
  npm install circuitjson-toolkit
54
97
  ```
55
98
 
56
- ## Usage
99
+ Node.js 20 or newer is required.
57
100
 
58
- Parse a standalone CircuitJSON file or string:
101
+ ## Parse and reuse a context
59
102
 
60
103
  ```js
61
104
  import {
62
- CircuitJsonDocument,
63
- CircuitJsonIndexer,
64
- CircuitJsonParser
105
+ CircuitJsonDocumentContext,
106
+ Parser,
107
+ PcbInteractionIndex,
108
+ PcbSvgRenderer,
109
+ QueryService
65
110
  } from 'circuitjson-toolkit'
66
111
 
67
- const circuitJson = CircuitJsonParser.parseText(fileText)
68
- CircuitJsonDocument.assertModel(circuitJson)
69
-
70
- const index = CircuitJsonIndexer.index(circuitJson)
71
- console.log(index.elementsByType.get('pcb_board'))
72
- ```
73
-
74
- The parser also accepts bytes, mirroring the parser style used by the source
75
- ECAD toolkits:
76
-
77
- ```js
78
- import { CircuitJsonParser } from 'circuitjson-toolkit'
112
+ const document = Parser.parse({
113
+ fileName: 'board.json',
114
+ data: fileText
115
+ })
79
116
 
80
- const documentModel = CircuitJsonParser.parseBytes(arrayBuffer, {
81
- fileName: file.name
117
+ const context = CircuitJsonDocumentContext.prepare(document, {
118
+ indexes: ['elements', 'relations', 'connectivity', 'spatial']
82
119
  })
83
- ```
84
120
 
85
- Parser-focused imports are available through the `parser` subpath:
121
+ const svg = PcbSvgRenderer.render(context, { side: 'top' })
122
+ const hits = PcbInteractionIndex.create(context).hitTest({ x: 10, y: 5 })
123
+ const components = QueryService.create(context).query({
124
+ select: 'components'
125
+ })
86
126
 
87
- ```js
88
- import { CircuitJsonParser } from 'circuitjson-toolkit/parser'
127
+ console.log(document.model, svg, hits, components.items)
89
128
  ```
90
129
 
91
- Build an index for renderer or reporting integrations:
130
+ `Parser.parse()` returns the exact clone-safe `ecad-toolkit.document.v1`
131
+ envelope:
92
132
 
93
133
  ```js
94
- import { CircuitJsonIndexer } from 'circuitjson-toolkit'
95
-
96
- const index = CircuitJsonIndexer.index(documentModel)
97
- const board = index.elementsByType.get('pcb_board')?.[0]
98
- const components = index.elementsByType.get('pcb_component') || []
99
- const source = index.sourceComponentById.get('source_component_1')
134
+ {
135
+ schema: 'ecad-toolkit.document.v1',
136
+ id: 'document-...',
137
+ modelSchema: { name: 'circuit-json', version: '0.0.446' },
138
+ model: [],
139
+ source: { format: 'circuitjson', fileName: 'board.json', fileType: 'circuitjson' },
140
+ extensions: {},
141
+ assets: [],
142
+ diagnostics: [],
143
+ statistics: {}
144
+ }
100
145
  ```
101
146
 
102
- Convert CircuitJSON millimeter coordinates for renderer adapters:
147
+ ## Project and asynchronous parsing
103
148
 
104
149
  ```js
105
- import { CircuitJsonUnits } from 'circuitjson-toolkit'
106
-
107
- const centerMil = CircuitJsonUnits.pointMmToMil(board.center)
108
- const widthMil = CircuitJsonUnits.mmToMil(board.width)
150
+ import { Parser, ProjectLoader } from 'circuitjson-toolkit'
151
+
152
+ const project = ProjectLoader.load(
153
+ [
154
+ {
155
+ name: 'board.json',
156
+ data: boardText,
157
+ assets: [{ name: 'body.step', data: bodyBytes }]
158
+ },
159
+ { name: 'schematic.json', data: schematicText }
160
+ ],
161
+ { decodeAssets: 'metadata' }
162
+ )
163
+
164
+ const controller = new AbortController()
165
+ const document = await Parser.parseAsync(
166
+ { fileName: 'board.json', data: boardBytes },
167
+ {
168
+ worker: 'auto',
169
+ transferInput: false,
170
+ signal: controller.signal,
171
+ onProgress: ({ stage, detail }) => console.log(stage, detail)
172
+ }
173
+ )
174
+
175
+ console.log(project.documents, document.model)
109
176
  ```
110
177
 
111
- Run a local SPICE transient example and receive CircuitJSON experiment output:
178
+ Attached asset bytes count toward both `maxEntryBytes` and `maxTotalBytes` in
179
+ direct and worker project loading, even when `decodeAssets: 'none'` omits them
180
+ from the result.
181
+
182
+ Direct and worker calls return equivalent serialized results. Caller input is
183
+ never detached unless `transferInput: true` is explicit. `worker: 'auto'`
184
+ falls back to direct execution only when worker construction is unavailable;
185
+ explicit worker and runtime failures remain visible.
186
+
187
+ Selected source-native extensions are captured once into an immutable owned
188
+ snapshot. Their separate 128 MiB payload and 2,000,000-item ceilings permit
189
+ realistic renderer/model graphs without weakening the worker protocol's 250 MB
190
+ total-result ceiling; an over-limit extension fails visibly instead of being
191
+ silently truncated. Binary extension values remain byte-backed and return
192
+ defensive copies instead of expanding into JavaScript number arrays.
193
+ When extensions are disabled, native documents and projects return the exact
194
+ empty map `{}`. Bounded ZIP consumers can preflight local/central filenames and
195
+ CRC32/size metadata with
196
+ `ZipArchiveInspector.inspect()` and validate inflated bytes with
197
+ `verifyExtractedBytes()`. Compression limits use member payload sizes, so ZIP
198
+ comments or other container padding cannot dilute the measured expansion ratio.
199
+
200
+ The shared PCB hole primitive preserves circular, pill/oval, rectangular, and
201
+ square legal variants. Square holes normalize to equal-width rectangular
202
+ apertures instead of circular fallbacks.
203
+
204
+ `retainSource: 'reference'` is available for direct parser calls that need the
205
+ exact caller input identity. It adds a non-enumerable `sourceReference`, does
206
+ not freeze the caller object, and is omitted from serialized results. Explicit
207
+ worker execution rejects this identity-only mode; automatic execution stays
208
+ direct.
209
+
210
+ ## Render, inspect, export, simulate, and build scenes
112
211
 
113
212
  ```js
114
- import { SpiceSimulationService } from 'circuitjson-toolkit'
213
+ import {
214
+ BomTableRenderer,
215
+ ManufacturingService,
216
+ PcbScene3dBuilder,
217
+ PcbScene3dPreparator,
218
+ SchematicSvgRenderer,
219
+ SimulationService
220
+ } from 'circuitjson-toolkit'
115
221
 
116
- const result = await SpiceSimulationService.simulate(`
117
- Vmain out 0 DC 3.3
118
- .PRINT TRAN V(out)
119
- .tran 1ms 2ms
120
- .END
121
- `)
222
+ const schematicSvg = SchematicSvgRenderer.render(document)
223
+ const bomHtml = BomTableRenderer.render(document)
224
+ const manufacturing = ManufacturingService.inspect(document)
225
+ const simulation = SimulationService.build(document)
226
+ const canonicalScene = PcbScene3dBuilder.build(document)
122
227
 
123
- console.log(result.simulationCircuitJson)
124
- console.log(result.graphSummary)
228
+ const preparedScene = await PcbScene3dPreparator.prepare(document, {
229
+ fidelity: 'native',
230
+ resolveAsset: async (request, { signal }) =>
231
+ await hostAssetStore.resolve(request, { signal })
232
+ })
125
233
  ```
126
234
 
127
- Pass CircuitJSON to the 3D renderer as a separate step:
235
+ 3D results use the `ecad-toolkit.scene3d.v1` data contract. Runtime rendering
236
+ belongs to packages such as
237
+ [`pcb-scene3d-viewer`](https://www.npmjs.com/package/pcb-scene3d-viewer).
128
238
 
129
- ```js
130
- import { CircuitJsonParser } from 'circuitjson-toolkit'
131
- import { PcbScene3dController } from 'pcb-scene3d-viewer'
239
+ ## Retained extension APIs
132
240
 
133
- const circuitJson = CircuitJsonParser.parseText(fileText, {
134
- fileName: 'board.circuitjson'
135
- })
241
+ Previous specialized exports remain available explicitly:
136
242
 
137
- const controller = new PcbScene3dController(viewportNode, circuitJson)
243
+ ```js
244
+ import {
245
+ CircuitJsonParser,
246
+ CircuitJsonPcbSvgRenderer,
247
+ SpiceSimulationService
248
+ } from 'circuitjson-toolkit/extensions'
138
249
  ```
139
250
 
140
- `circuitjson-toolkit` does not render, fetch, or load external model assets.
141
- That behavior belongs in host applications or renderer packages.
251
+ New integrations should use canonical classes. `/extensions` exists for
252
+ deliberate migrations, not as a second common API. Its exact 37 exports are
253
+ source-neutral and can be shared or derived by all four toolkits.
254
+
255
+ The temporary root compatibility class also exposes
256
+ `CircuitJsonDocument.normalizeModel(model, { owned })`. It projects supported
257
+ pre-union table, PCB path, pad-clearance, courtyard, and artwork aliases onto
258
+ the pinned CircuitJSON union. The default copy-on-write mode returns the exact
259
+ input when it is already canonical; `{ owned: true }` is reserved for
260
+ toolkit-owned mutable projections and may update them in place. Renderers and
261
+ viewers can therefore share the same normalization boundary instead of keeping
262
+ application adapters.
263
+
264
+ The compatibility renderer also provides
265
+ `CircuitJsonPcbSvgRenderer.renderSides(model, sides)` so callers migrating
266
+ multi-side output can prepare legacy primitives once.
267
+
268
+ `CircuitJsonPcbHolePrimitiveModel` is the shared geometry boundary for drilled
269
+ PCB elements. Polygon-plated pads derive rotation-local width and height from
270
+ `pad_outline`, while pill drill width, height, diameter, and rotation remain
271
+ available to viewers and manufacturing consumers without source adapters.
272
+
273
+ Direct asynchronous parsing and project loading own exact binary view windows
274
+ and selected assets before the first progress callback. Worker-received inputs
275
+ reuse their structured-clone ownership marker, avoiding a redundant receiver
276
+ copy while keeping sync, direct async, and worker results mutation-isolated.
277
+
278
+ ## Package entrypoints
279
+
280
+ - `circuitjson-toolkit`
281
+ - `circuitjson-toolkit/parser`
282
+ - `circuitjson-toolkit/project`
283
+ - `circuitjson-toolkit/renderers`
284
+ - `circuitjson-toolkit/interaction`
285
+ - `circuitjson-toolkit/query`
286
+ - `circuitjson-toolkit/manufacturing`
287
+ - `circuitjson-toolkit/simulation`
288
+ - `circuitjson-toolkit/scene3d`
289
+ - `circuitjson-toolkit/capabilities`
290
+ - `circuitjson-toolkit/extensions`
291
+ - `circuitjson-toolkit/testing`
292
+ - `circuitjson-toolkit/workers/parser.worker.mjs`
293
+ - `circuitjson-toolkit/styles/renderers.css`
142
294
 
143
295
  ## Documentation
144
296
 
145
- - [API](docs/api.md)
146
- - [Model Format](docs/model-format.md)
147
- - [Testing](docs/testing.md)
148
- - [Scope](spec/library-scope.md)
149
-
150
- ## Package Scope
297
+ - [API reference](docs/api.md)
298
+ - [Capability inventory](docs/capabilities.md)
299
+ - [Migration from 1.0.17](docs/migration.md)
300
+ - [Model and envelope format](docs/model-format.md)
301
+ - [Testing and downstream conformance](docs/testing.md)
302
+ - [1.1.0 release notes](docs/release-notes-v1.1.0.md)
303
+ - [1.1.1 release notes](docs/release-notes-v1.1.1.md)
304
+ - [Library scope](spec/library-scope.md)
151
305
 
152
- This package owns reusable CircuitJSON utility behavior only:
306
+ ## Package scope
153
307
 
154
- - parser-style document ingestion for serialized CircuitJSON;
155
- - validation and diagnostics for element-array inputs;
156
- - indexing and lookup maps for common CircuitJSON IDs;
157
- - small unit conversion helpers for downstream renderer adapters.
158
- - local SPICE transient graph helpers that return CircuitJSON elements.
308
+ This package owns common, data-only operations derived from CircuitJSON. Native
309
+ Gerber, Altium, and KiCad decoding remains in the source toolkit. Native-only
310
+ facts remain in `document.extensions[format]`; common services do not duplicate
311
+ or rename native renderer graphs.
159
312
 
160
- It does not include native Altium or KiCad parsing, schematic/PCB SVG
161
- rendering, Three.js rendering, browser UI controls, network fetching, or
162
- format-specific scene-description builders.
313
+ The package does not own Three.js runtime rendering, browser UI controls,
314
+ implicit filesystem access, implicit network access, or source-format-specific
315
+ decoders.
163
316
 
164
317
  ## Test
165
318
 
166
319
  ```bash
167
320
  npm test
321
+ npm run check:format
322
+ npm run sync:schema -- --check
323
+ npm run check:features -- --strict
324
+ npm run benchmark -- --compare benchmarks/baseline-v1.0.17.json
325
+ npm run check:packed-entrypoints
326
+ npm run check:browser-dependencies
168
327
  ```
169
328
 
170
- The test suite uses small fake CircuitJSON samples only. Do not add customer,
171
- vendor, or source project documents to this repository.
329
+ Tests use small synthetic CircuitJSON and source-format fixtures only. Do not
330
+ add customer, vendor, or source project documents.
172
331
 
173
332
  ## License
174
333
 
@@ -197,6 +356,14 @@ Commercial licensing contact: https://github.com/SunboX
197
356
  See [COMMERCIAL-LICENSE.md](COMMERCIAL-LICENSE.md). That file is a licensing
198
357
  notice, not a commercial license grant.
199
358
 
359
+ ### Downstream toolkit dependency
360
+
361
+ Gerber Toolkit, Altium Toolkit, and KiCad Toolkit use this package as their
362
+ shared runtime. Their package or commercial terms do not replace this
363
+ package's AGPL or separately granted commercial terms. A closed-source product
364
+ using a source toolkit must also have an AGPL-compatible use or a separate
365
+ commercial license for CircuitJSON Toolkit.
366
+
200
367
  ### Documentation and notices
201
368
 
202
369
  Documentation and non-code text are licensed under Creative Commons