pcb-scene3d-viewer 1.1.49 → 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.
- package/README.md +46 -21
- package/docs/api.md +109 -8
- package/docs/circuitjson.md +143 -29
- package/docs/model-format.md +50 -7
- package/docs/release-notes-v1.2.0.md +122 -0
- package/docs/testing.md +30 -1
- package/package.json +6 -3
- package/spec/library-scope.md +10 -2
- package/src/CircuitJsonCadModelAssetResolver.mjs +697 -83
- package/src/PcbAssemblyBoardSubstrateBuilder.mjs +43 -0
- package/src/PcbAssemblyGeometryBuilder.mjs +40 -18
- package/src/PcbAssemblyModelMeshLoader.mjs +101 -150
- package/src/PcbAssemblyPadMeshBuilder.mjs +22 -0
- package/src/PcbModelArchiveExporter.mjs +28 -112
- package/src/PcbModelArchiveSourceBundle.mjs +326 -0
- package/src/PcbScene3dAabbIndex.mjs +464 -0
- package/src/PcbScene3dBoardAssemblyPresentation.mjs +1 -1
- package/src/PcbScene3dBoardEdgeCutoutBuilder.mjs +9 -5
- package/src/PcbScene3dBoardMaterialPalette.mjs +29 -0
- package/src/PcbScene3dBoardShapeFactory.mjs +11 -118
- package/src/PcbScene3dBoardSolderMaskFactory.mjs +65 -39
- package/src/PcbScene3dCircuitJsonAdapter.mjs +151 -48
- package/src/PcbScene3dCircuitJsonDrillDetail.mjs +31 -0
- package/src/PcbScene3dCircuitJsonGeometry.mjs +184 -33
- package/src/PcbScene3dCircuitJsonInput.mjs +132 -0
- package/src/PcbScene3dCircuitJsonModelAsset.mjs +40 -0
- package/src/PcbScene3dController.mjs +40 -34
- package/src/PcbScene3dCopperFactory.mjs +36 -22
- package/src/PcbScene3dCopperFillAreaClipper.mjs +133 -235
- package/src/PcbScene3dCopperFillCoverageContext.mjs +204 -0
- package/src/PcbScene3dCopperFillLoopSetResolver.mjs +192 -0
- package/src/PcbScene3dCopperFillMeshBuilder.mjs +77 -295
- package/src/PcbScene3dCopperTextFactory.mjs +12 -4
- package/src/PcbScene3dCutoutCircleDetector.mjs +34 -17
- package/src/PcbScene3dCutoutGeometryFilter.mjs +104 -269
- package/src/PcbScene3dCutoutGridIndex.mjs +184 -0
- package/src/PcbScene3dDeferredModelFinalizer.mjs +52 -0
- package/src/PcbScene3dDescriptorSafeRecord.mjs +38 -0
- package/src/PcbScene3dDrillCutoutFilter.mjs +149 -143
- package/src/PcbScene3dDrillPathFactory.mjs +86 -16
- package/src/PcbScene3dDrillVoidFactory.mjs +35 -10
- package/src/PcbScene3dExternalModelGroupLoader.mjs +472 -31
- package/src/PcbScene3dExternalModels.mjs +23 -24
- package/src/PcbScene3dFacetedModelGroupBuilder.mjs +217 -0
- package/src/PcbScene3dGeometryZCompressor.mjs +4 -2
- package/src/PcbScene3dMaskCoveredCopperSideGroupBuilder.mjs +18 -4
- package/src/PcbScene3dMaskCoveredCopperSurfaceFilter.mjs +75 -10
- package/src/PcbScene3dModelContent.mjs +236 -0
- package/src/PcbScene3dModelFetchPolicy.mjs +304 -0
- package/src/PcbScene3dModelIdentity.mjs +106 -0
- package/src/PcbScene3dPlatedDrillSpecResolver.mjs +141 -0
- package/src/PcbScene3dPreparedPolygon.mjs +709 -0
- package/src/PcbScene3dPreparedPolygonSet.mjs +70 -0
- package/src/PcbScene3dRuntime.mjs +45 -45
- package/src/PcbScene3dRuntimeBoardMeshes.mjs +85 -1
- package/src/PcbScene3dShapeHoleGeometryCleaner.mjs +4 -2
- package/src/PcbScene3dShellRenderer.mjs +75 -6
- package/src/PcbScene3dSilkscreenCutoutContext.mjs +255 -0
- package/src/PcbScene3dSilkscreenFactory.mjs +87 -127
- package/src/PcbScene3dSilkscreenFillSeamBuilder.mjs +11 -5
- package/src/PcbScene3dStepLoader.mjs +11 -10
- package/src/PcbScene3dText.mjs +1 -1
- package/src/PcbScene3dTriangleVertexQueryBounds.mjs +302 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 André Fiedler
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# PCB Scene3D Viewer 1.2.0
|
|
7
|
+
|
|
8
|
+
Version 1.2.0 aligns the viewer boundary with the converged ECAD toolkit APIs.
|
|
9
|
+
|
|
10
|
+
## API changes
|
|
11
|
+
|
|
12
|
+
- `PcbScene3dCircuitJsonAdapter.isCircuitJsonModel()` and `build()` now accept
|
|
13
|
+
`ecad-toolkit.document.v1` results and prepared
|
|
14
|
+
`CircuitJsonDocumentContext` instances in addition to CircuitJSON arrays.
|
|
15
|
+
- `PcbScene3dCircuitJsonAdapter.prepare()` exposes the proof-aware shared
|
|
16
|
+
normalization/index boundary. Predicates stay non-mutating and no longer
|
|
17
|
+
reject a shared-normalizable legacy row before preparation.
|
|
18
|
+
- `PcbScene3dController` and `PcbScene3dRuntime` automatically route canonical
|
|
19
|
+
document envelopes through the direct CircuitJSON path without requiring a
|
|
20
|
+
source-format scene builder.
|
|
21
|
+
- Controller preparation now consistently prefers an explicit
|
|
22
|
+
`sceneDescription`, then `scenePrepClient`, then canonical CircuitJSON, and
|
|
23
|
+
finally the legacy source builder. Adapter options and session assets survive
|
|
24
|
+
asynchronous preparation fallback.
|
|
25
|
+
- `PcbScene3dShellRenderer` accepts the same legacy, raw CircuitJSON, canonical
|
|
26
|
+
document, and prepared-context inputs as the controller, including
|
|
27
|
+
component-only `drawFauxBoard` scenes.
|
|
28
|
+
- Legacy hybrid arrays that carry `pcb`, `schematic`, or `bom` compatibility
|
|
29
|
+
fields still use the host-provided source-format builder.
|
|
30
|
+
- Live external model loading now matches every adapter-advertised format:
|
|
31
|
+
STEP/STP, WRL/VRML, STL, OBJ, GLTF/GLB, and 3MF. Canonical bytes, session
|
|
32
|
+
files, and explicitly enabled model URLs use one consistent runtime policy.
|
|
33
|
+
- Text-capable loaders accept canonical `text`, `payloadText`, and string
|
|
34
|
+
`data`; raw ZIP export accepts `text`, `payloadText`, `data`, `bytes`,
|
|
35
|
+
`payloadBytes`, files, and explicitly enabled URLs. Archive extensions now
|
|
36
|
+
preserve every advertised format, including 3MF.
|
|
37
|
+
- `modelLoaderOptions` is forwarded from `PcbScene3dController` to runtime and
|
|
38
|
+
archive export. Controller archive names now recognize canonical
|
|
39
|
+
`source.fileName` on documents and prepared contexts.
|
|
40
|
+
- Resolved GLTF BIN, OBJ MTL, and WRL texture companions are attached from safe
|
|
41
|
+
project-relative session/document assets. WRL textures never trigger an
|
|
42
|
+
implicit Three.js network load; local or explicitly fetched bytes are embedded
|
|
43
|
+
as data URIs first.
|
|
44
|
+
- Injected WRL loaders now receive sanitized source with an empty resource base
|
|
45
|
+
path. Hosts that previously relied on Three.js resolving relative textures
|
|
46
|
+
implicitly must supply local resources or an explicit `modelLoaderOptions`
|
|
47
|
+
fetch policy.
|
|
48
|
+
- Static `authHeaders` no longer cross the main model origin. The new
|
|
49
|
+
`authHeadersForUrl` callback is the explicit cross-origin authorization path.
|
|
50
|
+
- URL fetch scopes enforce safe defaults of 128 MiB per resource, 256 resources,
|
|
51
|
+
and 512 MiB aggregate across main sources and sidecars. The limits are
|
|
52
|
+
configurable with `maxModelBytes`, `maxModelResources`, and
|
|
53
|
+
`maxModelTotalBytes`.
|
|
54
|
+
- Raw ZIP entries now use unique pattern directories and original source
|
|
55
|
+
basenames. Safe relative GLTF buffers/images, OBJ resources, and WRL textures
|
|
56
|
+
are included beside the main source; return rows expose `bundleDirectory` and
|
|
57
|
+
`companionPaths`.
|
|
58
|
+
- Polygon-plated holes now consume the shared CircuitJSON hole primitive model.
|
|
59
|
+
`pad_outline` determines rotation-local copper extents, polygon pads stay
|
|
60
|
+
non-circular, and pill drill width/height survive as slot geometry. A 2.6 by
|
|
61
|
+
0.6 mm Gerber routed slot no longer collapses to a 1 by 1 mm circular pad.
|
|
62
|
+
- Slot drill angles are board-space and applied exactly once; diagonal and
|
|
63
|
+
vertical routed slots no longer double-rotate with their outer pads. Separate
|
|
64
|
+
rectangular-pad and drill rotations remain independent.
|
|
65
|
+
- Plated-wall classification uses that same board-space drill rotation instead
|
|
66
|
+
of adding the outer pad rotation again. Legal rectangular and square holes
|
|
67
|
+
retain exact aperture width, height, and rotation through substrate and pad
|
|
68
|
+
geometry and assembly export.
|
|
69
|
+
- Every disjoint CircuitJSON board or panel contour now produces its own board
|
|
70
|
+
body, outline, solder-mask faces, and assembly-export substrate mesh. Panel
|
|
71
|
+
rows take physical precedence over their child board rows without data loss.
|
|
72
|
+
|
|
73
|
+
## Performance and validation
|
|
74
|
+
|
|
75
|
+
- Scene adaptation uses `CircuitJsonDocumentContext` as the validation boundary
|
|
76
|
+
and requests only the shared `elements` index.
|
|
77
|
+
- Repeated builds from one prepared context reuse that index instead of
|
|
78
|
+
validating and indexing the model again.
|
|
79
|
+
- Controller routing prepares a canonical document once and passes the context
|
|
80
|
+
forward, eliminating duplicate full-model predicate validation.
|
|
81
|
+
- Descriptor-safe CircuitJSON normalization keeps legacy hidden metadata from
|
|
82
|
+
bypassing or breaking the immutable shared model boundary.
|
|
83
|
+
- CircuitJSON detection predicates validate without freezing or otherwise
|
|
84
|
+
mutating caller-owned arrays and unprepared document envelopes.
|
|
85
|
+
- `CircuitJsonCadModelAssetResolver.withModelAssetUrls()` now preserves common
|
|
86
|
+
document envelopes and prepared-context return shapes while deriving explicit
|
|
87
|
+
model URL fields from retained `model_asset` metadata.
|
|
88
|
+
- The adapter consumes canonical `model_asset` records directly and resolves
|
|
89
|
+
canonical document assets plus session assets through one descriptor-safe
|
|
90
|
+
alias index. Documents without model references skip asset indexing,
|
|
91
|
+
prepared contexts cache the canonical index across builds, and payload copies
|
|
92
|
+
stay lazy until a matching model is used. Resolver wrappers, hostile session
|
|
93
|
+
arrays, option proxies, and metadata accessors cannot execute caller accessors.
|
|
94
|
+
ECAD Forge no longer needs an app-side document transform or resolver wrapper.
|
|
95
|
+
- Canonical accessor-backed `ToolkitAsset` session payloads are materialized
|
|
96
|
+
lazily through the shared asset contract before descriptor-safe viewer
|
|
97
|
+
copying. Exact STEP and other model bytes now flow from converged project
|
|
98
|
+
loaders without weakening hostile-accessor rejection.
|
|
99
|
+
- Restored route-via, legacy layer, silkscreen/courtyard, oval, copper-pour, and
|
|
100
|
+
default-via fixtures now rely on structural normalization in
|
|
101
|
+
`circuitjson-toolkit` instead of viewer-side compatibility workarounds.
|
|
102
|
+
- A context-asset benchmark guards the one-index-build repeated-render path.
|
|
103
|
+
- Model group, STEP parse, request-cache, and archive identities prefer exact
|
|
104
|
+
canonical paths, source streams, and asset IDs. Same-basename files in
|
|
105
|
+
different directories remain distinct, identical sources are reused, and
|
|
106
|
+
rejected shared requests are evicted for retry.
|
|
107
|
+
- Asset aliases preserve exact case-sensitive paths. Case-insensitive fallback
|
|
108
|
+
resolves only one unique owner and refuses ambiguous case-fold collisions.
|
|
109
|
+
- Canonical shell BOM counts now use `CircuitJsonBomBuilder`, matching toolkit
|
|
110
|
+
grouping behavior instead of counting raw source-component rows.
|
|
111
|
+
- Relative GLTF sidecars resolve beside relative as well as absolute main model
|
|
112
|
+
paths. Existing local buffers are reused before any explicitly enabled fetch.
|
|
113
|
+
- The empty archive diagnostic is format-neutral because export is no longer
|
|
114
|
+
limited to STEP and WRL.
|
|
115
|
+
|
|
116
|
+
## Dependencies
|
|
117
|
+
|
|
118
|
+
- Requires `circuitjson-toolkit ^1.1.0` and Node.js 20 or newer.
|
|
119
|
+
- Pins `earcut` 3.0.2 so npm deduplication cannot change deterministic triangle
|
|
120
|
+
ordering while the CircuitJSON dependency graph is upgraded.
|
|
121
|
+
- The package version advances from 1.1.50 to 1.2.0 because accepted input
|
|
122
|
+
shapes and direct-routing behavior changed incompatibly.
|
package/docs/testing.md
CHANGED
|
@@ -11,13 +11,42 @@ The test suite covers:
|
|
|
11
11
|
- geometry factories for board solids, pads, vias, drills, solder mask,
|
|
12
12
|
copper, and silkscreen;
|
|
13
13
|
- runtime camera, preset, resizing, selection, and visibility behavior;
|
|
14
|
-
- external STEP/WRL
|
|
14
|
+
- external STEP/STP, WRL/VRML, STL, OBJ, GLTF/GLB, and 3MF live loading;
|
|
15
15
|
- model ZIP archive export;
|
|
16
16
|
- optional shell renderer and CSS contract;
|
|
17
17
|
- worker-client request routing.
|
|
18
|
+
- canonical document/context/array parity and prepared-index reuse.
|
|
19
|
+
- direct canonical `model_asset`, document-asset, and session-asset resolution.
|
|
20
|
+
- descriptor-safe asset alias and resolved-metadata handling.
|
|
21
|
+
- lazy, context-cached canonical asset indexing and exact documentation samples.
|
|
22
|
+
- path-exact model/cache/archive identities and same-basename collision cases.
|
|
23
|
+
- local-only companion attachment, WRL texture network blocking, explicit URL
|
|
24
|
+
fetch/cache retries, and project-relative GLTF sidecars.
|
|
25
|
+
- same-origin static authentication, explicit per-URL headers, and per-resource,
|
|
26
|
+
resource-count, and aggregate fetch limits shared with sidecars.
|
|
27
|
+
- raw archive parity for canonical text, bytes, data, files, URLs, and 3MF,
|
|
28
|
+
including source basenames and safe GLTF/OBJ/WRL companion subtrees.
|
|
29
|
+
- shared-normalizable legacy routing, proof-aware preparation, exact-case asset
|
|
30
|
+
selection, ambiguity-safe folded lookup, and faux-board shell parity.
|
|
31
|
+
- canonical polygon-plated pill slots, including rotation-local pad extents,
|
|
32
|
+
independent outer/drill angles, and 45/90-degree board-space regressions;
|
|
33
|
+
- legal rectangular and square drill apertures through adapter, substrate,
|
|
34
|
+
pad-local, plating, drill-void, and assembly-export boundaries;
|
|
35
|
+
- disjoint multi-board and multi-panel substrate, outline, solder-mask, and
|
|
36
|
+
export geometry, plus the real Gerber project-to-viewer path in ECAD Forge.
|
|
18
37
|
|
|
19
38
|
Tests use fake scene descriptions and fake model payloads only. Do not add
|
|
20
39
|
customer, vendor, or source-derived fixture identifiers.
|
|
21
40
|
|
|
22
41
|
Use focused tests for behavior changes. Parser and scene-description builder
|
|
23
42
|
tests belong in the format-specific toolkits, not in this viewer package.
|
|
43
|
+
|
|
44
|
+
Run performance guards with:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm run benchmark:exact-geometry
|
|
48
|
+
npm run benchmark:context-assets
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The context-asset benchmark verifies that unreferenced assets are never indexed
|
|
52
|
+
and repeated builds reuse one context-owned canonical alias index.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pcb-scene3d-viewer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Reusable Three.js PCB 3D scene viewer for normalized ECAD and CircuitJSON scene descriptions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pcb",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"src",
|
|
34
34
|
"docs/api.md",
|
|
35
35
|
"docs/circuitjson.md",
|
|
36
|
+
"docs/release-notes-v1.2.0.md",
|
|
36
37
|
"docs/model-format.md",
|
|
37
38
|
"docs/testing.md",
|
|
38
39
|
"spec",
|
|
@@ -47,13 +48,15 @@
|
|
|
47
48
|
],
|
|
48
49
|
"scripts": {
|
|
49
50
|
"test": "node --test",
|
|
51
|
+
"benchmark:exact-geometry": "node scripts/benchmark-exact-geometry.mjs",
|
|
52
|
+
"benchmark:context-assets": "node scripts/benchmark-context-model-assets.mjs",
|
|
50
53
|
"format": "prettier --write .",
|
|
51
54
|
"check:format": "prettier --check ."
|
|
52
55
|
},
|
|
53
56
|
"dependencies": {
|
|
54
57
|
"@sunbox/occt-import-js": "^0.0.25",
|
|
55
|
-
"circuitjson-toolkit": "^1.0
|
|
56
|
-
"earcut": "
|
|
58
|
+
"circuitjson-toolkit": "^1.1.0",
|
|
59
|
+
"earcut": "3.0.2",
|
|
57
60
|
"fflate": "^0.8.2",
|
|
58
61
|
"polygon-clipping": "^0.15.7",
|
|
59
62
|
"three": "^0.183.2"
|
package/spec/library-scope.md
CHANGED
|
@@ -8,13 +8,20 @@ scene descriptions.
|
|
|
8
8
|
- Three.js runtime orchestration for PCB scenes.
|
|
9
9
|
- Board, copper, via, drill, silkscreen, solder-mask, and fallback package mesh
|
|
10
10
|
factories.
|
|
11
|
-
- STEP, WRL,
|
|
11
|
+
- STEP/STP, WRL/VRML, 3MF, GLB/GLTF, STL, and OBJ model loading and placement
|
|
12
|
+
from canonical bytes, session files, or explicitly enabled URLs.
|
|
12
13
|
- Camera presets, view compensation, selection styling, picking, and visibility
|
|
13
14
|
toggles.
|
|
14
15
|
- Optional DOM shell/controller helpers for hosts that want ready-made scene
|
|
15
16
|
chrome.
|
|
16
17
|
- ZIP export of resolved component model assets.
|
|
18
|
+
- Self-contained raw model bundle export with safe relative GLTF, OBJ, and WRL
|
|
19
|
+
companions.
|
|
17
20
|
- CSS for the optional scene shell.
|
|
21
|
+
- Direct common CircuitJSON document, prepared context, and element-array
|
|
22
|
+
adaptation with shared index reuse.
|
|
23
|
+
- Direct canonical CAD `model_asset` and document/session asset resolution.
|
|
24
|
+
- Explicit origin-aware and bounded network model loading.
|
|
18
25
|
|
|
19
26
|
## Out of Scope
|
|
20
27
|
|
|
@@ -22,12 +29,13 @@ scene descriptions.
|
|
|
22
29
|
- Building format-specific 3D scene descriptions from source documents.
|
|
23
30
|
- Host application state, routing, file pickers, drag/drop handling, analytics,
|
|
24
31
|
localization storage, or app navigation.
|
|
25
|
-
- Server-side upload or
|
|
32
|
+
- Server-side upload behavior or host-owned URL authorization/proxy policy.
|
|
26
33
|
|
|
27
34
|
## Host Contract
|
|
28
35
|
|
|
29
36
|
Hosts provide either:
|
|
30
37
|
|
|
38
|
+
- a common CircuitJSON `DocumentResult`, prepared context, or element array;
|
|
31
39
|
- a prepared scene description through `sceneDescription`;
|
|
32
40
|
- a `scenePrepClient` with `prepareScene(documentModel, sessionAssets)`; or
|
|
33
41
|
- `buildScene(documentModel, { modelRegistry })` plus an optional
|