pcb-scene3d-viewer 1.0.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 (65) hide show
  1. package/AGENTS.md +67 -0
  2. package/COMMERCIAL-LICENSE.md +15 -0
  3. package/CONTRIBUTING.md +14 -0
  4. package/LICENSE +19 -0
  5. package/LICENSES/AGPL-3.0-or-later.txt +235 -0
  6. package/LICENSES/CC-BY-SA-4.0.txt +170 -0
  7. package/LICENSES/LGPL-2.1-or-later.txt +176 -0
  8. package/LICENSES/LicenseRef-PolyForm-Noncommercial-1.0.0.txt +131 -0
  9. package/NOTICE.md +36 -0
  10. package/README.md +128 -0
  11. package/REUSE.toml +16 -0
  12. package/docs/api.md +148 -0
  13. package/docs/circuitjson.md +190 -0
  14. package/docs/model-format.md +117 -0
  15. package/docs/testing.md +23 -0
  16. package/package.json +65 -0
  17. package/spec/library-scope.md +36 -0
  18. package/src/PcbModelArchiveExporter.mjs +320 -0
  19. package/src/PcbScene3dArcUtils.mjs +27 -0
  20. package/src/PcbScene3dBoardAssemblyPlacement.mjs +36 -0
  21. package/src/PcbScene3dBoardAssemblyPresentation.mjs +859 -0
  22. package/src/PcbScene3dBoardEdgeCutoutBuilder.mjs +537 -0
  23. package/src/PcbScene3dBoardMaterialPalette.mjs +40 -0
  24. package/src/PcbScene3dBoardShapeFactory.mjs +895 -0
  25. package/src/PcbScene3dBoardSolderMaskFactory.mjs +613 -0
  26. package/src/PcbScene3dCameraRig.mjs +168 -0
  27. package/src/PcbScene3dCircuitJsonAdapter.mjs +545 -0
  28. package/src/PcbScene3dController.mjs +956 -0
  29. package/src/PcbScene3dCopperDetailFilter.mjs +490 -0
  30. package/src/PcbScene3dCopperFactory.mjs +559 -0
  31. package/src/PcbScene3dCopperTextFactory.mjs +534 -0
  32. package/src/PcbScene3dCutoutGeometryFilter.mjs +873 -0
  33. package/src/PcbScene3dDetailCoordinateNormalizer.mjs +65 -0
  34. package/src/PcbScene3dDrillCutoutFilter.mjs +224 -0
  35. package/src/PcbScene3dDrillPathFactory.mjs +362 -0
  36. package/src/PcbScene3dDrillVoidFactory.mjs +268 -0
  37. package/src/PcbScene3dExternalModelLoadOrder.mjs +54 -0
  38. package/src/PcbScene3dExternalModels.mjs +968 -0
  39. package/src/PcbScene3dFallbackVisibility.mjs +82 -0
  40. package/src/PcbScene3dInteractionHints.mjs +56 -0
  41. package/src/PcbScene3dMountRig.mjs +53 -0
  42. package/src/PcbScene3dOutlineBuilder.mjs +210 -0
  43. package/src/PcbScene3dPadFactory.mjs +553 -0
  44. package/src/PcbScene3dPresetState.mjs +48 -0
  45. package/src/PcbScene3dRenderGroupVisibility.mjs +134 -0
  46. package/src/PcbScene3dRuntime.mjs +996 -0
  47. package/src/PcbScene3dRuntimeBoardMeshes.mjs +99 -0
  48. package/src/PcbScene3dSelectionStyler.mjs +252 -0
  49. package/src/PcbScene3dShapePathFactory.mjs +220 -0
  50. package/src/PcbScene3dShellRenderer.mjs +131 -0
  51. package/src/PcbScene3dSilkscreenFactory.mjs +854 -0
  52. package/src/PcbScene3dSilkscreenStrokeWidthResolver.mjs +81 -0
  53. package/src/PcbScene3dStepLoader.mjs +611 -0
  54. package/src/PcbScene3dStrokeFont.mjs +671 -0
  55. package/src/PcbScene3dStrokeGeometryBuilder.mjs +322 -0
  56. package/src/PcbScene3dText.mjs +99 -0
  57. package/src/PcbScene3dTrueTypeTextFactory.mjs +885 -0
  58. package/src/PcbScene3dViaFactory.mjs +176 -0
  59. package/src/PcbScene3dViewCompensation.mjs +109 -0
  60. package/src/PcbScene3dViewScale.mjs +24 -0
  61. package/src/PcbScene3dViewportResize.mjs +35 -0
  62. package/src/PcbScene3dWorkerClient.mjs +123 -0
  63. package/src/index.mjs +1 -0
  64. package/src/scene3d.mjs +44 -0
  65. package/src/styles/scene3d.css +295 -0
@@ -0,0 +1,190 @@
1
+ # CircuitJSON Usage
2
+
3
+ `pcb-scene3d-viewer` can render serialized CircuitJSON element arrays directly.
4
+ Use this path when the host application already has CircuitJSON and does not
5
+ need an Altium, KiCad, or other format-specific scene builder.
6
+
7
+ ## Direct Controller Input
8
+
9
+ Pass the CircuitJSON array as the `documentModel`. The controller detects direct
10
+ CircuitJSON input, converts it to the internal render model, and mounts the
11
+ runtime without a `buildScene` callback.
12
+
13
+ ```js
14
+ import {
15
+ PcbScene3dController,
16
+ PcbScene3dShellRenderer
17
+ } from 'pcb-scene3d-viewer'
18
+
19
+ const circuitJson = [
20
+ {
21
+ type: 'pcb_board',
22
+ width: 50,
23
+ height: 30,
24
+ thickness: 1.6,
25
+ center: { x: 25, y: 15 }
26
+ },
27
+ {
28
+ type: 'source_component',
29
+ id: 'source-r1',
30
+ name: 'R1',
31
+ ftype: 'R_0603'
32
+ },
33
+ {
34
+ type: 'pcb_component',
35
+ source_component_id: 'source-r1',
36
+ layer: 1,
37
+ center: { x: 20, y: 15 },
38
+ rotation: 90,
39
+ width: 1.6,
40
+ height: 0.8,
41
+ component_height: 0.55
42
+ },
43
+ {
44
+ type: 'pcb_smtpad',
45
+ layer: 1,
46
+ x: 19.2,
47
+ y: 15,
48
+ width: 0.7,
49
+ height: 0.9
50
+ },
51
+ {
52
+ type: 'pcb_smtpad',
53
+ layer: 1,
54
+ x: 20.8,
55
+ y: 15,
56
+ width: 0.7,
57
+ height: 0.9
58
+ },
59
+ {
60
+ type: 'pcb_trace',
61
+ layer: 1,
62
+ route: [
63
+ { x: 18, y: 15 },
64
+ { x: 19.2, y: 15 }
65
+ ],
66
+ width: 0.25
67
+ }
68
+ ]
69
+
70
+ container.innerHTML = PcbScene3dShellRenderer.render(circuitJson)
71
+
72
+ const controller = new PcbScene3dController(
73
+ container.querySelector('[data-scene-3d-viewport]'),
74
+ circuitJson
75
+ )
76
+ ```
77
+
78
+ The shell renderer does not inspect the CircuitJSON data. It only renders the
79
+ optional DOM controls. The controller performs the CircuitJSON detection and
80
+ conversion.
81
+
82
+ ## Direct Runtime Input
83
+
84
+ For custom UI shells, pass the same CircuitJSON array directly to
85
+ `PcbScene3dRuntime`.
86
+
87
+ ```js
88
+ import { PcbScene3dRuntime } from 'pcb-scene3d-viewer'
89
+
90
+ const runtime = new PcbScene3dRuntime(viewportNode, circuitJson, {
91
+ setDiagnostics: (messages) => renderDiagnostics(messages),
92
+ setSelection: (selection) => renderSelection(selection)
93
+ })
94
+
95
+ await runtime.whenReady()
96
+ runtime.setPreset('isometric')
97
+ ```
98
+
99
+ ## Adapter API
100
+
101
+ The direct path uses `PcbScene3dCircuitJsonAdapter`. Hosts can call it directly
102
+ when they need to inspect or cache the normalized render model.
103
+
104
+ ```js
105
+ import { PcbScene3dCircuitJsonAdapter } from 'pcb-scene3d-viewer'
106
+
107
+ if (PcbScene3dCircuitJsonAdapter.isCircuitJsonModel(circuitJson)) {
108
+ const sceneDescription = PcbScene3dCircuitJsonAdapter.build(circuitJson)
109
+ }
110
+ ```
111
+
112
+ `isDirectCircuitJsonModel(value)` returns `false` for compatibility arrays that
113
+ also carry legacy parser fields such as `pcb`, `schematic`, or `bom`. Those
114
+ arrays continue through the host-provided `buildScene` callback so existing
115
+ parser integrations keep their source-specific conversion behavior.
116
+
117
+ ## Units And Coordinates
118
+
119
+ CircuitJSON input uses millimeters. The adapter converts all board, component,
120
+ pad, via, trace, and silkscreen dimensions into mils before handing the scene to
121
+ the Three.js runtime.
122
+
123
+ The board center defaults to `{ x: 0, y: 0 }` when omitted. If no `pcb_board`
124
+ element is present, the adapter creates a 25.4 mm by 25.4 mm board with a
125
+ 1.6 mm thickness so incomplete test or preview models still render.
126
+
127
+ Layer values resolve as follows:
128
+
129
+ - `1`, `top`, `front`, and `f.cu` map to the top side.
130
+ - `32`, `bottom`, `back`, and `b.cu` map to the bottom side.
131
+ - Unknown layer values default to the top side.
132
+
133
+ ## Supported Elements
134
+
135
+ The adapter focuses on renderer-ready PCB geometry and ignores unsupported
136
+ CircuitJSON elements instead of failing the whole scene.
137
+
138
+ | Element type | Rendered as |
139
+ | --------------------- | --------------------------------------------------- |
140
+ | `pcb_board` | Board size, thickness, center, and optional outline |
141
+ | `source_component` | Component designator and package metadata |
142
+ | `pcb_component` | Fallback component body and selection target |
143
+ | `pcb_smtpad` | Top or bottom SMT pad copper |
144
+ | `pcb_plated_hole` | Through-hole pad copper and drill |
145
+ | `pcb_hole` | Non-plated drill opening |
146
+ | `pcb_via` | Via copper and drill |
147
+ | `pcb_trace` | Routed copper track segments |
148
+ | `pcb_silkscreen_line` | Top or bottom silkscreen stroke |
149
+ | `pcb_silkscreen_text` | Top or bottom silkscreen text placeholder |
150
+
151
+ Board outlines can be supplied as `pcb_board.outline`, using an array of points:
152
+
153
+ ```js
154
+ {
155
+ type: 'pcb_board',
156
+ outline: [
157
+ { x: 0, y: 0 },
158
+ { x: 50, y: 0 },
159
+ { x: 50, y: 30 },
160
+ { x: 0, y: 30 }
161
+ ]
162
+ }
163
+ ```
164
+
165
+ Traces can be supplied as a `route` array. Each adjacent point pair becomes one
166
+ track segment:
167
+
168
+ ```js
169
+ {
170
+ type: 'pcb_trace',
171
+ layer: 'top',
172
+ route: [
173
+ { x: 5, y: 5 },
174
+ { x: 10, y: 5 },
175
+ { x: 10, y: 8 }
176
+ ],
177
+ width: 0.2
178
+ }
179
+ ```
180
+
181
+ ## Diagnostics
182
+
183
+ Malformed CircuitJSON input is rejected by `circuitjson-toolkit` before render
184
+ model conversion. Use `PcbScene3dCircuitJsonAdapter.isCircuitJsonModel(value)`
185
+ for a cheap guard when accepting untrusted JSON from users, and catch conversion
186
+ errors around `build(value)` when you need to show a custom diagnostic.
187
+
188
+ The viewer does not fetch external assets for CircuitJSON input. STEP and WRL
189
+ model matching remains the responsibility of source-specific toolkits or host
190
+ applications that create normalized scene descriptions.
@@ -0,0 +1,117 @@
1
+ # Model Format
2
+
3
+ The viewer consumes a normalized PCB 3D scene description. Format-specific
4
+ toolkits are responsible for creating this data.
5
+
6
+ ## Top-Level Shape
7
+
8
+ ```js
9
+ {
10
+ sourceFormat: 'altium' | 'kicad' | string,
11
+ coordinateSystem: 'kicad-3d-y-up' | undefined,
12
+ board: {
13
+ widthMil,
14
+ heightMil,
15
+ thicknessMil,
16
+ minX,
17
+ minY,
18
+ centerX,
19
+ centerY,
20
+ segments,
21
+ surfaceColor,
22
+ edgeColor
23
+ },
24
+ components: [],
25
+ externalPlacements: [],
26
+ boardAssemblyModel: null,
27
+ detail: {
28
+ pads: [],
29
+ tracks: [],
30
+ arcs: [],
31
+ fills: [],
32
+ vias: [],
33
+ polygons: [],
34
+ copperTexts: [],
35
+ silkscreen: {
36
+ top: {},
37
+ bottom: {}
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ All dimensions are in mils. The runtime centers board detail around
44
+ `board.centerX` and `board.centerY`.
45
+
46
+ ## Components
47
+
48
+ Components describe fallback package bodies and selection metadata:
49
+
50
+ ```js
51
+ {
52
+ designator: 'U1',
53
+ mountSide: 'top',
54
+ rotationDeg: 90,
55
+ positionMil: { x: 0, y: 0, z: 90 },
56
+ boardPositionMil: { x: 500, y: 500, z: 0 },
57
+ pattern: 'SOIC-8',
58
+ source: 'library',
59
+ body: {
60
+ family: 'ic',
61
+ sizeMil: { width: 200, depth: 300, height: 60 }
62
+ },
63
+ externalModel: null
64
+ }
65
+ ```
66
+
67
+ ## External Placements
68
+
69
+ External placements describe STEP or WRL model instances:
70
+
71
+ ```js
72
+ {
73
+ designator: 'U1',
74
+ mountSide: 'top',
75
+ rotationDeg: 90,
76
+ positionMil: { x: 0, y: 0, z: 31.5 },
77
+ bodyPositionMil: { x: 500, y: 500 },
78
+ bodyRotationDeg: 0,
79
+ modelTransform: {
80
+ rotationDeg: { x: 90, y: 0, z: 0 },
81
+ dzMil: 0
82
+ },
83
+ externalModel: {
84
+ origin: 'session',
85
+ name: 'soic-8.step',
86
+ relativePath: 'packages/soic-8.step',
87
+ format: 'step',
88
+ file: File
89
+ }
90
+ }
91
+ ```
92
+
93
+ Embedded STEP models can use:
94
+
95
+ ```js
96
+ {
97
+ origin: 'embedded',
98
+ name: 'embedded.step',
99
+ format: 'step',
100
+ payloadText: 'ISO-10303-21;'
101
+ }
102
+ ```
103
+
104
+ ## Detail Primitives
105
+
106
+ The runtime expects pre-normalized primitive lists for:
107
+
108
+ - pads and vias with drill and copper dimensions;
109
+ - tracks and arcs with layer metadata;
110
+ - fills and polygons with point loops;
111
+ - silkscreen tracks, arcs, fills, and texts;
112
+ - copper text primitives.
113
+
114
+ The viewer does not infer source-file semantics. When a scene needs
115
+ format-specific layer mapping, solder-mask interpretation, text layout, or
116
+ model matching, the source toolkit should encode those decisions in the scene
117
+ description.
@@ -0,0 +1,23 @@
1
+ # Testing
2
+
3
+ Run all tests with:
4
+
5
+ ```bash
6
+ npm test
7
+ ```
8
+
9
+ The test suite covers:
10
+
11
+ - geometry factories for board solids, pads, vias, drills, solder mask,
12
+ copper, and silkscreen;
13
+ - runtime camera, preset, resizing, selection, and visibility behavior;
14
+ - external STEP/WRL placement and load ordering;
15
+ - model ZIP archive export;
16
+ - optional shell renderer and CSS contract;
17
+ - worker-client request routing.
18
+
19
+ Tests use fake scene descriptions and fake model payloads only. Do not add
20
+ customer, vendor, or source-derived fixture identifiers.
21
+
22
+ Use focused tests for behavior changes. Parser and scene-description builder
23
+ tests belong in the format-specific toolkits, not in this viewer package.
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "pcb-scene3d-viewer",
3
+ "version": "1.0.1",
4
+ "description": "Reusable Three.js PCB 3D scene viewer for normalized ECAD and CircuitJSON scene descriptions",
5
+ "keywords": [
6
+ "pcb",
7
+ "ecad",
8
+ "eda",
9
+ "circuitjson",
10
+ "3d",
11
+ "three",
12
+ "viewer",
13
+ "step",
14
+ "wrl"
15
+ ],
16
+ "homepage": "https://github.com/SunboX/pcb-scene3d-viewer#readme",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/SunboX/pcb-scene3d-viewer.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/SunboX/pcb-scene3d-viewer/issues"
23
+ },
24
+ "license": "AGPL-3.0-or-later",
25
+ "type": "module",
26
+ "main": "./src/index.mjs",
27
+ "exports": {
28
+ ".": "./src/index.mjs",
29
+ "./scene3d": "./src/scene3d.mjs",
30
+ "./styles/scene3d.css": "./src/styles/scene3d.css"
31
+ },
32
+ "files": [
33
+ "src",
34
+ "docs/api.md",
35
+ "docs/circuitjson.md",
36
+ "docs/model-format.md",
37
+ "docs/testing.md",
38
+ "spec",
39
+ "LICENSE",
40
+ "LICENSES",
41
+ "COMMERCIAL-LICENSE.md",
42
+ "CONTRIBUTING.md",
43
+ "NOTICE.md",
44
+ "README.md",
45
+ "AGENTS.md",
46
+ "REUSE.toml"
47
+ ],
48
+ "scripts": {
49
+ "test": "node --test",
50
+ "format": "prettier --write .",
51
+ "check:format": "prettier --check ."
52
+ },
53
+ "dependencies": {
54
+ "circuitjson-toolkit": "^1.0.1",
55
+ "fflate": "^0.8.2",
56
+ "occt-import-js": "^0.0.23",
57
+ "three": "^0.183.2"
58
+ },
59
+ "devDependencies": {
60
+ "prettier": "^3.4.2"
61
+ },
62
+ "engines": {
63
+ "node": ">=20"
64
+ }
65
+ }
@@ -0,0 +1,36 @@
1
+ # Library Scope
2
+
3
+ `pcb-scene3d-viewer` owns reusable browser-side 3D rendering for normalized PCB
4
+ scene descriptions.
5
+
6
+ ## In Scope
7
+
8
+ - Three.js runtime orchestration for PCB scenes.
9
+ - Board, copper, via, drill, silkscreen, solder-mask, and fallback package mesh
10
+ factories.
11
+ - STEP and WRL model loading and placement.
12
+ - Camera presets, view compensation, selection styling, picking, and visibility
13
+ toggles.
14
+ - Optional DOM shell/controller helpers for hosts that want ready-made scene
15
+ chrome.
16
+ - ZIP export of resolved STEP and WRL model assets.
17
+ - CSS for the optional scene shell.
18
+
19
+ ## Out of Scope
20
+
21
+ - Parsing Altium, KiCad, Gerber, or other ECAD source files.
22
+ - Building format-specific 3D scene descriptions from source documents.
23
+ - Host application state, routing, file pickers, drag/drop handling, analytics,
24
+ localization storage, or app navigation.
25
+ - Server-side upload or network fetch behavior.
26
+
27
+ ## Host Contract
28
+
29
+ Hosts provide either:
30
+
31
+ - a prepared scene description through `sceneDescription`;
32
+ - a `scenePrepClient` with `prepareScene(documentModel, sessionAssets)`; or
33
+ - `buildScene(documentModel, { modelRegistry })` plus an optional
34
+ `createModelRegistry(documentModel, sessionAssets)`.
35
+
36
+ The viewer treats all scene descriptions and model payloads as untrusted input.