altium-toolkit 1.1.41 → 1.2.0

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 (58) hide show
  1. package/README.md +113 -19
  2. package/docs/api.md +224 -18
  3. package/docs/capabilities.md +65 -0
  4. package/docs/migration/legacy-001.md +309 -0
  5. package/docs/migration/legacy-002.md +309 -0
  6. package/docs/migration/legacy-003.md +309 -0
  7. package/docs/migration/legacy-004.md +309 -0
  8. package/docs/migration/legacy-005.md +111 -0
  9. package/docs/migration.md +20 -0
  10. package/docs/model-format.md +28 -3
  11. package/docs/release-notes-v1.2.0.md +147 -0
  12. package/docs/testing.md +43 -1
  13. package/examples/arduino-uno/PcbThreeSceneRenderer.mjs +1 -1
  14. package/examples/arduino-uno/example.mjs +1 -1
  15. package/examples/cli-utils.mjs +1 -1
  16. package/examples/corpus-smoke.mjs +1 -1
  17. package/examples/inspect-board.mjs +1 -1
  18. package/examples/library-catalog.mjs +1 -1
  19. package/examples/validate-library.mjs +1 -1
  20. package/package.json +20 -5
  21. package/spec/api-baseline-v1.1.41.json +1 -0
  22. package/spec/asset-baseline-v1.1.41.json +1 -0
  23. package/spec/feature-preservation.json +1 -0
  24. package/spec/library-scope.md +14 -4
  25. package/spec/native-source-manifest-v1.1.41.json +1 -0
  26. package/src/capabilities.mjs +4 -0
  27. package/src/convergence/AltiumCircuitJsonProjection.mjs +230 -0
  28. package/src/convergence/AltiumDocumentBuilder.mjs +167 -0
  29. package/src/convergence/AltiumExtensionResolver.mjs +98 -0
  30. package/src/convergence/AltiumProjectDocumentResolver.mjs +324 -0
  31. package/src/convergence/AltiumSchematicCoordinateProjection.mjs +130 -0
  32. package/src/convergence/AltiumWorkerClient.mjs +95 -0
  33. package/src/convergence/Parser.mjs +285 -0
  34. package/src/convergence/ParserInput.mjs +282 -0
  35. package/src/convergence/ProjectLoader.mjs +916 -0
  36. package/src/convergence/SchematicSvgRenderer.mjs +126 -0
  37. package/src/convergence/ToolkitCapabilities.mjs +49 -0
  38. package/src/core/circuit-json/CircuitJsonSchematicDocumentGraphicBuilder.mjs +785 -0
  39. package/src/core/circuit-json/CircuitJsonSchematicGraphicBuilder.mjs +909 -0
  40. package/src/core/circuit-json/CircuitJsonSchematicImageProjection.mjs +277 -0
  41. package/src/core/circuit-json/CircuitJsonSchematicStrokeStyle.mjs +47 -0
  42. package/src/extensions.mjs +11 -0
  43. package/src/index.mjs +20 -4
  44. package/src/interaction.mjs +7 -0
  45. package/src/legacy-netlist-query.mjs +11 -0
  46. package/src/legacy-parser.mjs +141 -0
  47. package/src/legacy-renderers.mjs +25 -0
  48. package/src/legacy-scene3d.mjs +10 -0
  49. package/src/manufacturing.mjs +4 -0
  50. package/src/parser.mjs +12 -138
  51. package/src/project.mjs +11 -0
  52. package/src/query.mjs +4 -0
  53. package/src/renderers.mjs +4 -22
  54. package/src/scene3d.mjs +5 -8
  55. package/src/simulation.mjs +4 -0
  56. package/src/styles/renderers.css +27 -0
  57. package/src/testing.mjs +8 -0
  58. package/src/workers/parser.worker.mjs +37 -0
package/README.md CHANGED
@@ -6,20 +6,87 @@ SPDX-License-Identifier: CC-BY-SA-4.0
6
6
 
7
7
  # Altium Toolkit
8
8
 
9
- Altium Toolkit is an ESM JavaScript library for parsing native Altium
10
- schematic and PCB documents and rendering deterministic, non-interactive
11
- outputs from the recovered model.
9
+ Altium Toolkit is the native Altium decoder in the common ECAD toolkit family.
10
+ It parses Altium files into immutable CircuitJSON document envelopes and common
11
+ project envelopes, and exposes the same parser, renderer, interaction, query,
12
+ simulation, 3D scene, capability, error, and worker contracts as
13
+ `circuitjson-toolkit`, `gerber-toolkit`, and `kicad-toolkit`.
12
14
 
13
15
  The package was extracted from [ECAD Forge](https://ecadforge.app/), where it
14
16
  is used for browser-based Altium document parsing and deterministic render
15
17
  output. It is also used in [PCB Styler](https://pcb-styler.app/). Its parser
16
18
  behavior, normalized model shape, and renderer output can be reused by other
17
- browser or Node-based tools.
19
+ browser or Node-based tools. Parsing and all default services are local-only.
20
+
21
+ ## Breaking API convergence
22
+
23
+ Version 1.2.0 intentionally changes root names, parameters, return shapes, and
24
+ package subpaths. The root now contains the exact 17-class shared toolkit
25
+ surface, and `Parser.parse()` returns an `ecad-toolkit.document.v1` envelope whose `model`
26
+ is CircuitJSON. No Altium feature was deleted: all 1.1.41 exports and public
27
+ members remain under `altium-toolkit/extensions`, alongside the 37 shared
28
+ source-neutral extension helpers, with the exhaustive native mapping in the
29
+ [migration guide](docs/migration.md).
30
+
31
+ Default `extensions: 'canonical'` keeps compact Altium summary metadata.
32
+ Request the complete native read model with `extensions: 'full'`,
33
+ `preserveRaw: true`, or `extensions: ['altium.native-model']`. Project batches
34
+ resolve referenced schematic project strings consistently in canonical
35
+ CircuitJSON and an explicitly retained native model; select
36
+ `altium.project-context` only when the compact native parameter/document facts
37
+ are also needed.
38
+ `extensions: 'none'` and an empty selection return the exact common
39
+ `extensions: {}` shape on documents and projects.
40
+
41
+ Hosts that need an Altium-only renderer for details not represented by
42
+ CircuitJSON can resolve the explicit extension without changing the canonical
43
+ document shape:
44
+
45
+ ```js
46
+ import { Parser } from 'altium-toolkit'
47
+ import { AltiumExtensionResolver } from 'altium-toolkit/extensions'
48
+
49
+ const document = Parser.parse(input, {
50
+ extensions: ['altium.native-model']
51
+ })
52
+ const nativeModel = AltiumExtensionResolver.nativeModel(document)
53
+ ```
54
+
55
+ `document` remains an immutable `ecad-toolkit.document.v1` result; native
56
+ `schematic` and `pcb` fields are never copied onto it.
57
+
58
+ `SchematicSvgRenderer` from `altium-toolkit/extensions` is the native
59
+ convergence renderer. It honors recovered component-designator visibility and
60
+ delegates to the provenance-pinned historical renderer without requiring a
61
+ host to clone or rewrite the native model.
62
+
63
+ The common parser now projects native schematic rectangles, rounded
64
+ rectangles, circles and ellipses, arcs, Beziers, polygons, text frames, tables
65
+ when present, hierarchical child-sheet symbols, and ordinary text into the
66
+ same CircuitJSON rows used by KiCad. Component ownership, stroke/fill style,
67
+ geometry, and stable render order are retained. Embedded schematic image bytes
68
+ are owned once as `ToolkitAsset` records with `kind: 'schematic-image'`; their
69
+ `schematic_image` rows reference `asset_id` and retain source path, bounds,
70
+ aspect policy, and order without duplicating base64 data in the model.
71
+ Only native wire records become canonical electrical traces; graphical lines
72
+ remain artwork even when they carry net-like metadata, and PCB source-trace
73
+ relations are preserved unchanged in mixed documents.
18
74
 
19
75
  ## Features
20
76
 
21
- - Parse standalone native `.SchDoc`, `.PcbDoc`, `.SchLib`, `.PcbLib`,
22
- `.PrjPcb`, and `.IntLib` files from `ArrayBuffer`
77
+ - Exact common `Parser` and `ProjectLoader` contracts with immutable
78
+ CircuitJSON document envelopes, common project envelopes, progress,
79
+ cancellation, archive limits, ZIP preflight inspection, and workers
80
+ - Shared CircuitJSON context, rendering, interaction, query, manufacturing,
81
+ injected simulation, and right-handed Z-up 3D scene services
82
+ - One native Altium parse per canonical request; compact default extensions
83
+ avoid cloning the complete native tree unless explicitly requested
84
+ - Explicit large native extensions are captured once as bounded immutable
85
+ CircuitJSON document data and survive the shared worker protocol
86
+ - Machine-readable capability inventory, packed conformance harness,
87
+ provenance-bound performance gates, and explicit `/extensions` compatibility
88
+ - Parse standalone native `.SchDoc`, `.PcbDoc`, `.PCBDwf`, `.SchLib`,
89
+ `.PcbLib`, `.PrjPcb`, `.PrjScr`, and `.IntLib` files from `ArrayBuffer`
23
90
  - Recover schematic records, PCB outlines, placements, schematic library
24
91
  symbols, PCB library footprints,
25
92
  project document references, variants, parameters, primitives, embedded
@@ -37,6 +104,9 @@ browser or Node-based tools.
37
104
  schematic-library section keys, pin side streams, compressed storage assets,
38
105
  schematic project-parameter text resolution, PCB QA statistics, structured
39
106
  diagnostics, and embedded PCB/PcbLib font payloads with basic text metrics
107
+ - Project rich native schematic graphics and asset-backed images directly into
108
+ the shared CircuitJSON renderer contract, including distinct hierarchical
109
+ `schematic_sheet_symbol` rows whose child file names do not become page rows
40
110
  - Preserve raw PCB primitive records through a read-only record registry so
41
111
  unsupported or partially decoded stream data remains inspectable; native OLE
42
112
  stream inventories summarize known, unknown, consumed, and opaque streams
@@ -77,34 +147,55 @@ npm install @sunbox/altium-toolkit
77
147
 
78
148
  ```js
79
149
  import {
80
- AltiumParser,
81
- SchematicSvgRenderer,
150
+ CircuitJsonDocumentContext,
151
+ Parser,
152
+ PcbInteractionIndex,
153
+ PcbScene3dBuilder,
82
154
  PcbSvgRenderer,
83
- preparePcbSideResolvedRenderModel,
84
- BomTableRenderer,
85
- PcbScene3dBuilder
155
+ QueryService
86
156
  } from 'altium-toolkit'
87
157
 
88
- const documentModel = AltiumParser.parseArrayBuffer(file.name, arrayBuffer)
89
- const backRenderModel = preparePcbSideResolvedRenderModel(documentModel, {
90
- side: 'back'
158
+ const document = await Parser.parseAsync(
159
+ { fileName: file.name, data: arrayBuffer },
160
+ {
161
+ worker: 'auto',
162
+ onProgress: ({ stage }) => console.log(stage)
163
+ }
164
+ )
165
+ const context = CircuitJsonDocumentContext.prepare(document, {
166
+ indexes: ['elements', 'relations', 'connectivity', 'spatial']
91
167
  })
92
168
 
93
- const schematicMarkup = SchematicSvgRenderer.render(documentModel)
94
- const pcbMarkup = PcbSvgRenderer.render(backRenderModel)
95
- const bomMarkup = BomTableRenderer.render(documentModel.bom || [])
96
- const sceneDescription = PcbScene3dBuilder.build(documentModel)
169
+ const pcbMarkup = PcbSvgRenderer.render(context, { side: 'bottom' })
170
+ const hits = PcbInteractionIndex.create(context).hitTest({ x: 10, y: 5 })
171
+ const components = QueryService.create(context).query({
172
+ select: 'components'
173
+ })
174
+ const sceneDescription = PcbScene3dBuilder.build(context)
175
+
176
+ console.log(document.model, pcbMarkup, hits, components.items, sceneDescription)
97
177
  ```
98
178
 
99
179
  Optional renderer CSS is available through:
100
180
 
101
181
  ```js
102
- import 'altium-toolkit/styles/altium-renderers.css'
182
+ import 'altium-toolkit/styles/renderers.css'
183
+ ```
184
+
185
+ Use the retained native API deliberately when needed:
186
+
187
+ ```js
188
+ import { AltiumParser, AltiumSchLibExporter } from 'altium-toolkit/extensions'
189
+
190
+ const legacyCircuitJson = AltiumParser.parseArrayBuffer(file.name, arrayBuffer)
103
191
  ```
104
192
 
105
193
  ## Documentation
106
194
 
107
195
  - [API](docs/api.md)
196
+ - [Capabilities](docs/capabilities.md)
197
+ - [Migration from 1.1.41](docs/migration.md)
198
+ - [1.2.0 release notes](docs/release-notes-v1.2.0.md)
108
199
  - [Model Format](docs/model-format.md)
109
200
  - [Normalized Model Schema](docs/schemas/altium_toolkit/normalized_model_a1.schema.json)
110
201
  - [Project Bundle Schema](docs/schemas/altium_toolkit/project_bundle_a1.schema.json)
@@ -142,6 +233,9 @@ npm start
142
233
 
143
234
  ```bash
144
235
  npm test
236
+ npm run check:features -- --strict
237
+ npm run check:performance
238
+ npm run check:format
145
239
  ```
146
240
 
147
241
  The test suite uses repo-owned, obfuscated fixture shards only. Do not add
package/docs/api.md CHANGED
@@ -4,35 +4,238 @@ SPDX-FileCopyrightText: 2026 André Fiedler
4
4
  SPDX-License-Identifier: CC-BY-SA-4.0
5
5
  -->
6
6
 
7
- # API
7
+ # Canonical API
8
+
9
+ Version 1.2.0 exposes the same API contract as the other ECAD toolkits.
10
+ CircuitJSON is the shared immutable model. Common services accept a canonical
11
+ `DocumentResult`, its `model`, or a prepared `CircuitJsonDocumentContext` unless
12
+ the method documents a narrower input.
8
13
 
9
14
  ## Entrypoints
10
15
 
11
- `altium-toolkit` exports the supported parser, renderer, and 3D
12
- scene-description classes from one entrypoint.
16
+ The root exports exactly these 17 shared classes:
17
+
18
+ - `Parser`, `ProjectLoader`, `CircuitJsonDocument`,
19
+ `CircuitJsonDocumentContext`, `CircuitJsonIndexer`, and `CircuitJsonUnits`
20
+ - `PcbSvgRenderer`, `SchematicSvgRenderer`, and `BomTableRenderer`
21
+ - `PcbInteractionIndex` and `QueryService`
22
+ - `ManufacturingService` and `SimulationService`
23
+ - `PcbScene3dBuilder` and `PcbScene3dPreparator`
24
+ - `ToolkitCapabilities` and `ToolkitError`
13
25
 
14
26
  Specialized entrypoints are also available:
15
27
 
16
28
  - `altium-toolkit/parser`
17
- - `altium-toolkit/netlist-query`
29
+ - `altium-toolkit/project`
18
30
  - `altium-toolkit/renderers`
31
+ - `altium-toolkit/interaction`
32
+ - `altium-toolkit/query`
33
+ - `altium-toolkit/manufacturing`
34
+ - `altium-toolkit/simulation`
19
35
  - `altium-toolkit/scene3d`
20
- - `altium-toolkit/workers/altium-parser.worker.mjs`
21
- - `altium-toolkit/styles/altium-renderers.css`
36
+ - `altium-toolkit/capabilities`
37
+ - `altium-toolkit/testing`
38
+ - `altium-toolkit/workers/parser.worker.mjs`
39
+ - `altium-toolkit/styles/renderers.css`
40
+ - `altium-toolkit/extensions`
41
+
42
+ Altium-only worker and style assets are retained under
43
+ `altium-toolkit/extensions/workers/altium-parser.worker.mjs` and
44
+ `altium-toolkit/extensions/styles/altium-renderers.css`.
45
+
46
+ `altium-toolkit/parser` exposes the exact shared parser key set, including
47
+ `CircuitJsonDocumentContext`, while its `Parser` implementation remains
48
+ Altium-owned.
22
49
 
23
50
  ## Parser
24
51
 
25
52
  ```js
26
- import { AltiumParser } from 'altium-toolkit/parser'
53
+ import { Parser } from 'altium-toolkit/parser'
54
+
55
+ const document = Parser.parse({
56
+ fileName: 'design.PcbDoc',
57
+ data: arrayBuffer,
58
+ assets: []
59
+ })
60
+ ```
61
+
62
+ `Parser.parse(input, options?)` parses synchronously. `Parser.parseAsync()` adds
63
+ progress, cancellation, and worker execution. `Parser.tryParse()` returns
64
+ `{ ok: true, value }` or `{ ok: false, error, diagnostics }`, and
65
+ `Parser.supports()` performs bounded extension/data detection.
66
+
67
+ Common options are:
68
+
69
+ - `decodeAssets`: `'none'`, `'metadata'`, or `'full'`
70
+ - `extensions`: `'none'`, `'metadata'`, `'canonical'`, `'full'`, or a feature-id
71
+ array such as `['altium.native-model']` or
72
+ `['altium.project-context']`
73
+ - `preserveRaw`: include the complete native model without changing the common
74
+ document fields
75
+ - `reports`: explicit report ids; unavailable eager reports fail visibly
76
+ - `retainSource`: `'none'` or `'reference'`
77
+ - `worker`: `false`, `true`, or `'auto'`
78
+ - `transferInput`: permission to transfer worker input buffers
79
+ - `signal` and `onProgress`: cancellation and ordered progress
80
+
81
+ Asset inputs are validated through the shared descriptor-safe CircuitJSON
82
+ boundary. Metadata mode measures payloads without copying them and returns
83
+ `data: null`; full mode creates one defensive snapshot that downstream envelope
84
+ construction reuses. Project archive byte limits include every attached asset
85
+ before any payload snapshot is allocated.
86
+
87
+ Every successful call returns the exact common envelope:
88
+
89
+ ```js
90
+ {
91
+ schema: 'ecad-toolkit.document.v1',
92
+ id: 'document-...',
93
+ modelSchema: { name: 'circuit-json', version: '0.0.446' },
94
+ model: [],
95
+ source: {
96
+ format: 'altium',
97
+ fileName: 'design.PcbDoc',
98
+ fileType: 'pcbdoc'
99
+ },
100
+ extensions: { altium: { $meta: {}, summary: {} } },
101
+ assets: [],
102
+ diagnostics: [],
103
+ statistics: {}
104
+ }
105
+ ```
106
+
107
+ Default canonical mode keeps compact Altium `kind`, `fileType`, and `summary`
108
+ metadata. The complete recovered native read model remains available through
109
+ `extensions: 'full'`, `preserveRaw: true`, or the explicit
110
+ `altium.native-model` feature id. Common render/query/scene services operate on
111
+ `document.model` and do not require the full native extension.
112
+ `extensions: 'none'` or `extensions: []` returns exactly `extensions: {}`.
113
+
114
+ Canonical `.SchDoc` models preserve native drawing order, ownership, geometry,
115
+ and style as shared `schematic_rect`, `schematic_circle`, `schematic_arc`,
116
+ `schematic_path`, `schematic_text`, `schematic_table`, and
117
+ `schematic_sheet_symbol` elements. Cubic Beziers use 24 segments, unequal
118
+ ellipses use 48 points, and elliptical arcs use 7.5-degree sampling. Embedded
119
+ schematic images are `schematic_image` elements linked by `asset_id` to
120
+ document `ToolkitAsset` payloads, so image bytes are decoded according to the
121
+ same `decodeAssets` policy as every other asset and are never copied into the
122
+ CircuitJSON row. Missing external image references retain their source metadata
123
+ and produce a diagnostic instead of a placeholder or network request.
124
+ At the Altium convergence boundary, native record-27 segments receive
125
+ `sourceType: 'wire'`. The common graphic builder emits electrical
126
+ `schematic_trace`/`source_trace` rows only for that explicit classification;
127
+ net-like fields on artwork do not reclassify it. Existing PCB source-trace
128
+ relations remain unchanged when schematic graphics are rebuilt.
129
+
130
+ Public failures are `ToolkitError` instances with stable `code`, `category`,
131
+ `format`, `source`, `details`, and `cause` fields. Worker and direct execution
132
+ return the same serialized result. `worker: 'auto'` falls back only when worker
133
+ construction is unavailable; validation, parser, protocol, cancellation, post,
134
+ and runtime failures remain visible.
135
+
136
+ ## Projects
137
+
138
+ ```js
139
+ import { ProjectLoader } from 'altium-toolkit/project'
140
+
141
+ const project = await ProjectLoader.loadAsync(entries, {
142
+ worker: 'auto',
143
+ archiveLimits: { maxEntries: 512 },
144
+ onProgress: ({ stage, completed, total }) =>
145
+ console.log(stage, completed, total)
146
+ })
147
+ ```
148
+
149
+ The `/project` subpath also forwards the common `ArchiveEntryPath`,
150
+ `ArchiveLimits`, `ProjectResult`, and `ZipArchiveInspector` utilities. ZIP
151
+ preflight can therefore use the same central-directory limits and path policy
152
+ as other toolkit project loaders before any inflation step.
153
+
154
+ `load()`, `loadAsync()`, `tryLoad()`, and `supports()` use the same names and
155
+ shapes across the toolkit family. Entry paths are normalized and deduplicated;
156
+ entry count, source and attached-asset byte size, compression ratio, and archive
157
+ depth use shared hard ceilings that callers may tighten but cannot disable.
158
+ Supported documents may load partially, with per-entry errors returned as
159
+ project diagnostics. Non-Altium entries become companion assets according to
160
+ `decodeAssets`.
161
+
162
+ `tryLoad()` always returns at least one canonical error diagnostic on failure.
163
+ If a parser/project error already provides diagnostics they are preserved;
164
+ otherwise the public `ToolkitError` is projected into one diagnostic row.
165
+
166
+ When a project includes a `.PrjPcb` and referenced schematics, the loader
167
+ resolves visible schematic project strings such as `=ProjectName`,
168
+ `=DocumentName`, and declared project parameters before returning the canonical
169
+ documents. When `altium.native-model` is selected, the retained native
170
+ schematic and title-block fields contain the same resolved values. Compact
171
+ project facts live in the `altium.project-context` extension when selected,
172
+ but canonical text resolution is identical with `extensions: 'none'`;
173
+ consumers do not need an app-side project-context or native-model rewrite pass.
174
+
175
+ ## Reuse and common services
176
+
177
+ ```js
178
+ import {
179
+ CircuitJsonDocumentContext,
180
+ PcbInteractionIndex,
181
+ PcbSvgRenderer,
182
+ QueryService
183
+ } from 'altium-toolkit'
184
+
185
+ const context = CircuitJsonDocumentContext.prepare(document, {
186
+ indexes: ['elements', 'relations', 'connectivity', 'spatial']
187
+ })
188
+ const svg = PcbSvgRenderer.render(context, { side: 'top' })
189
+ const interaction = PcbInteractionIndex.create(context)
190
+ const query = QueryService.create(context)
191
+ ```
192
+
193
+ The context validates once and caches requested indexes and derived values.
194
+ The renderers, interaction service, query service, manufacturing service,
195
+ simulation service, and 3D scene builders are the CircuitJSON implementations
196
+ shared by all four packages. No service performs implicit network or filesystem
197
+ I/O; asset and simulation runtimes are injected explicitly.
198
+
199
+ ## Native extension API
200
+
201
+ The complete 1.1.41 namespace remains available from the explicit extension
202
+ entrypoint. Its 167 native exports are combined, without collisions, with the
203
+ 37 source-neutral CircuitJSON extension helpers and
204
+ `AltiumExtensionResolver` for 205 total extension exports. The generated
205
+ [migration guide](migration.md) maps every historical native export, member,
206
+ worker, stylesheet, and implementation contract.
207
+
208
+ ```js
209
+ import { AltiumParser } from 'altium-toolkit/extensions'
27
210
 
28
211
  const circuitJson = AltiumParser.parseArrayBuffer(fileName, arrayBuffer)
29
212
  ```
30
213
 
214
+ Canonical hosts retain source fidelity explicitly:
215
+
216
+ ```js
217
+ import { Parser } from 'altium-toolkit'
218
+ import { AltiumExtensionResolver } from 'altium-toolkit/extensions'
219
+
220
+ const document = Parser.parse(input, {
221
+ extensions: ['altium.native-model']
222
+ })
223
+ const nativeModel = AltiumExtensionResolver.nativeModel(document)
224
+ ```
225
+
226
+ The resolver returns `null` when the extension was not selected and never
227
+ attaches native fields to the canonical document.
228
+
229
+ Validated canonical documents own selected native extensions as a separate,
230
+ bounded immutable snapshot. Large native renderer graphs are captured once at
231
+ the document boundary, reused by the worker response path, and rejected with a
232
+ visible size error only when the shared extension ceiling is exceeded.
233
+
31
234
  `fileName` is used to infer schematic, PCB document, schematic symbol-library,
32
235
  PCB footprint-library, PCB project, or integrated-library parsing from the
33
- extension. The parser accepts native `.SchDoc`, `.PcbDoc`, `.SchLib`,
34
- `.PcbLib`, `.PrjPcb`, and `.IntLib` bytes as an `ArrayBuffer` and returns a
35
- Circuit JSON element array. The returned array carries non-serialized
236
+ extension. The parser accepts native `.SchDoc`, `.PcbDoc`, `.PCBDwf`, `.SchLib`,
237
+ `.PcbLib`, `.PrjPcb`, `.PrjScr`, and `.IntLib` bytes as an `ArrayBuffer` and
238
+ returns a Circuit JSON element array. The returned array carries non-serialized
36
239
  renderer-compatibility fields such as `kind`, `fileType`, `schematic`, `pcb`,
37
240
  `schematicLibrary`, `pcbLibrary`, `project`, `integratedLibrary`, `summary`,
38
241
  `diagnostics`, and `bom` so existing renderers can consume parser output
@@ -50,7 +253,7 @@ promoted to read-only `pcb.embeddedBoards` and `pcb.rooms` collections when
50
253
  present.
51
254
 
52
255
  ```js
53
- import { CircuitJsonModelSchema } from 'altium-toolkit/parser'
256
+ import { CircuitJsonModelSchema } from 'altium-toolkit/extensions'
54
257
 
55
258
  if (!CircuitJsonModelSchema.isModel(circuitJson)) {
56
259
  throw new Error('Unsupported Circuit JSON model')
@@ -231,7 +434,7 @@ import {
231
434
  AltiumSchLibExporter,
232
435
  AltiumPcbLibExporter,
233
436
  AltiumLibraryBatchExporter
234
- } from 'altium-toolkit/parser'
437
+ } from 'altium-toolkit/extensions'
235
438
  ```
236
439
 
237
440
  The exporter surface is local-first and host-controlled:
@@ -261,7 +464,7 @@ source. Tests use repo-owned fake responses only.
261
464
  ## Netlist Query
262
465
 
263
466
  ```js
264
- import { LoadedDesignNetlistService } from 'altium-toolkit/netlist-query'
467
+ import { LoadedDesignNetlistService } from 'altium-toolkit/extensions'
265
468
 
266
469
  const service = new LoadedDesignNetlistService({
267
470
  getDocuments: () => [
@@ -276,7 +479,7 @@ const service = new LoadedDesignNetlistService({
276
479
  const nets = service.searchNets({ pattern: 'i2c' })
277
480
  ```
278
481
 
279
- The `netlist-query` entrypoint exposes browser-safe helpers for loaded document
482
+ The extension entrypoint retains browser-safe helpers for loaded document
280
483
  inspection: `LoadedDesignNetlistService`, `QueryNetlistBuilder`,
281
484
  `CircuitTraversal`, `ComponentGrouping`, `MPN_MISSING_NOTE`, and
282
485
  `RegexPattern`.
@@ -297,12 +500,15 @@ import {
297
500
  preparePcbSideResolvedRenderModel,
298
501
  BomTableRenderer,
299
502
  PcbLayerGroups
300
- } from 'altium-toolkit/renderers'
503
+ } from 'altium-toolkit/extensions'
301
504
  ```
302
505
 
303
506
  - `SchematicSvgRenderer.render(documentModel, options)` returns schematic SVG
304
- markup. Pass `options.projectParameters` to resolve schematic special strings
305
- in visible text and title-block fields during rendering.
507
+ markup. The extension entrypoint exports a convergence facade that applies
508
+ recovered `schematicDesignatorVisible` semantics without mutating the input,
509
+ then delegates to the byte-identical historical renderer. Pass
510
+ `options.projectParameters` to resolve schematic special strings in visible
511
+ text and title-block fields during rendering.
306
512
  - `PcbSvgRenderer.render(documentModel)` returns PCB SVG markup.
307
513
  - `PcbSvgRenderer.renderLayerSvgs(documentModel)` returns deterministic
308
514
  per-layer PCB SVG entries with layer descriptors and layer-filtered SVG
@@ -346,7 +552,7 @@ import {
346
552
  PcbScene3dModelRegistry,
347
553
  PcbScene3dScenePreparator,
348
554
  PcbScene3dSummaryRenderer
349
- } from 'altium-toolkit/scene3d'
555
+ } from 'altium-toolkit/extensions'
350
556
  ```
351
557
 
352
558
  - `PcbScene3dBuilder.build(documentModel, options)` returns procedural board,
@@ -0,0 +1,65 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 André Fiedler
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Capabilities
7
+
8
+ `ToolkitCapabilities.inventory()` returns fresh clone-safe rows in stable id
9
+ order. The ids, categories, operations, and row shape are identical across
10
+ `circuitjson-toolkit`, `gerber-toolkit`, `altium-toolkit`, and `kicad-toolkit`.
11
+
12
+ Altium uses three truthful status levels:
13
+
14
+ - `native`: the package owns the source decoder, project loader, worker, or
15
+ Altium-specific exporter.
16
+ - `shared`: the operation runs on canonical CircuitJSON through
17
+ `circuitjson-toolkit`.
18
+ - `unavailable`: a capability cannot be represented honestly; callers receive
19
+ `ERR_CAPABILITY_UNAVAILABLE` instead of a placeholder result.
20
+
21
+ | Capability id | Altium implementation | Entrypoint |
22
+ | ---------------------- | --------------------- | ------------------------------------------ |
23
+ | `parse.document` | Native | `Parser` |
24
+ | `project.load` | Native | `ProjectLoader` |
25
+ | `worker.parse` | Native | `altium-toolkit/workers/parser.worker.mjs` |
26
+ | `worker.load-project` | Native | `altium-toolkit/workers/parser.worker.mjs` |
27
+ | `export.selected-part` | Native extension | `altium-toolkit/extensions` |
28
+ | `validation.document` | Shared CircuitJSON | `DocumentResult` |
29
+ | `metadata.normalize` | Shared CircuitJSON | `DocumentResult` |
30
+ | `units.convert` | Shared CircuitJSON | `CircuitJsonUnits` |
31
+ | `render.pcb` | Shared CircuitJSON | `PcbSvgRenderer` |
32
+ | `render.schematic` | Shared CircuitJSON | `SchematicSvgRenderer` |
33
+ | `bom.build` | Shared CircuitJSON | `BomTableRenderer` |
34
+ | `interaction.pcb` | Shared CircuitJSON | `PcbInteractionIndex` |
35
+ | `query.document` | Shared CircuitJSON | `QueryService` |
36
+ | `manufacturing.export` | Shared CircuitJSON | `ManufacturingService` |
37
+ | `simulation.spice` | Shared CircuitJSON | `SimulationService` |
38
+ | `scene3d.build` | Shared CircuitJSON | `PcbScene3dBuilder` |
39
+ | `scene3d.prepare` | Shared CircuitJSON | `PcbScene3dPreparator` |
40
+
41
+ The table describes the common surface, not the limit of Altium support. The
42
+ complete 1.1.41 native API remains at `altium-toolkit/extensions`. The
43
+ entrypoint is the collision-free union of 167 native exports and 37 shared
44
+ source-neutral helpers, plus `AltiumExtensionResolver` for explicit native
45
+ model access. Its 1,302 frozen historical exports, members, assets, and
46
+ native-source contracts are mapped in the
47
+ [migration appendix](migration.md). Exact Altium-only binary parsing, reports,
48
+ library writers, native SVG fidelity helpers, and native scene adapters are not
49
+ copied into unrelated source packages merely to claim parity. Functionality
50
+ that can operate truthfully on CircuitJSON is supplied to every package through
51
+ the shared canonical services instead.
52
+
53
+ ## Programmatic use
54
+
55
+ ```js
56
+ import { ToolkitCapabilities } from 'altium-toolkit/capabilities'
57
+
58
+ const rows = ToolkitCapabilities.inventory()
59
+ const parsing = rows.find((row) => row.id === 'parse.document')
60
+
61
+ console.log(parsing.status, parsing.entrypoint)
62
+ ```
63
+
64
+ Each row includes `id`, `category`, `operation`, `status`, `entrypoint`,
65
+ `summary`, `reason`, `tested`, and `documented`.