gds-lens 1.2.0 → 1.3.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/CHANGELOG.md +65 -0
- package/README.md +25 -10
- package/dist/esm/gds-lens.js +439 -66
- package/dist/inline-wasm/gds-lens-engine.js +0 -0
- package/dist/inline-wasm/gds-lens-worker.js +11 -1
- package/dist/inline-wasm/gds-lens.js +437 -64
- package/dist/web/gds-lens-engine.js +1 -1
- package/dist/web/gds-lens-engine.wasm +0 -0
- package/dist/web/gds-lens-worker.js +11 -1
- package/dist/web/gds-lens.js +437 -64
- package/docs/embedding.md +64 -0
- package/package.json +1 -1
- package/src/gds-lens.js +69 -12
- package/src/viewer.css +17 -0
- package/src/viewer.js +509 -58
- package/src/wasm-worker.js +9 -1
- package/types/gds-lens.d.ts +119 -6
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,71 @@ follows [semantic versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
From 1.0.0 on, a breaking change to the element's API waits for a major
|
|
8
8
|
version. Before that, `0.x` releases changed it freely.
|
|
9
9
|
|
|
10
|
+
## [1.3.0] - 2026-09-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Two layouts in one viewer.** A `<gds-lens>` can hold two layouts at once
|
|
15
|
+
and draw them through one camera into one canvas, for comparing two
|
|
16
|
+
revisions of a design:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
await element.load(oldBytes);
|
|
20
|
+
await element.load(newBytes, { slot: "b", name: "rev-b.gds" });
|
|
21
|
+
await element.setBlend(0.5);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- `load(source, { slot })` picks which layout to replace -- `"a"` (the
|
|
25
|
+
default, and the only one a single-layout viewer ever uses) or `"b"`. A
|
|
26
|
+
second layout arriving does not move the camera off what is already being
|
|
27
|
+
read, and loading either slot leaves the other alone.
|
|
28
|
+
- `unload(slot)` drops one again; `setBlend(t)` / `getBlend()` crossfade
|
|
29
|
+
between them, `0` showing only A, `1` only B, between overlaying them.
|
|
30
|
+
- With two loaded, the panel grows a **Compare** folder: the blend slider,
|
|
31
|
+
an optional per-layout tint, and **Highlight differences**, which marks
|
|
32
|
+
per (layer, datatype) where the two disagree -- one colour where only A
|
|
33
|
+
has geometry, another where only B does. Both rasterize through the same
|
|
34
|
+
camera into the same coverage mask in the same frame, so identical
|
|
35
|
+
geometry cancels exactly. It is a difference of what is drawn at the zoom
|
|
36
|
+
being viewed, not a geometric XOR, and differences under about half a
|
|
37
|
+
pixel are ignored; zoom in to resolve a smaller one.
|
|
38
|
+
- The layer list shows the **union** of both layouts' layers, chipped A or B
|
|
39
|
+
where only one has it, so an added or removed layer is visible as a row
|
|
40
|
+
rather than absent. The hierarchy browser roots both cell trees, and cell
|
|
41
|
+
and label searches run over both with the same chips on the hits.
|
|
42
|
+
- `getLayers()` entries gain `source` (0 for slot A, 1 for B), and
|
|
43
|
+
`gds-load`'s detail gains `slot`.
|
|
44
|
+
|
|
45
|
+
See [docs/embedding.md](docs/embedding.md#two-layouts-in-one-viewer). The
|
|
46
|
+
single-layout case is unchanged in every respect: no attribute, no mode
|
|
47
|
+
flag, and the Compare folder is not built at all until a second layout is
|
|
48
|
+
loaded.
|
|
49
|
+
|
|
50
|
+
- **gdsfactory / kfactory ports.** kfactory records each cell's ports as
|
|
51
|
+
KLayout meta info, which KLayout writes into the layout file itself: a
|
|
52
|
+
`$$$CONTEXT_INFO$$$` cell in GDSII, `KLAYOUT_CONTEXT` properties in OASIS,
|
|
53
|
+
each holding strings like `META('kfactory:ports:0')={'name'=>'o1',...}`. The
|
|
54
|
+
viewer now reads those back (`src/wasm/kfactory_ports.cpp`) -- name, type,
|
|
55
|
+
position, direction, width and layer, through the named cross-section --
|
|
56
|
+
and expands them through every placement, so a component's ports are marked
|
|
57
|
+
wherever it sits in the design: a bar across the port, an arrow the way it
|
|
58
|
+
faces, and its name once few enough are on screen to read. Optical ports
|
|
59
|
+
are orange, electrical green, anything else the highlight blue. A **Ports**
|
|
60
|
+
toggle in Display turns the overlay off; a **Ports** folder lists the top
|
|
61
|
+
cell's ports and centers the view on one when clicked. Each hierarchy cell
|
|
62
|
+
entry carries a `ports` array and the hierarchy a `portCount`, the
|
|
63
|
+
`gds-load` event's detail gains `portCount`, and the element exposes nothing
|
|
64
|
+
new otherwise -- a file without the metadata looks exactly as before. The
|
|
65
|
+
expansion stops at 200,000 port placements and says so in the panel.
|
|
66
|
+
|
|
67
|
+
- **`getCamera()` / `setCamera({zoom, panX, panY})`,
|
|
68
|
+
`getMeasurements()` / `addMeasurement(x0, y0, x1, y1)` /
|
|
69
|
+
`clearMeasurements()`, and `getLayers()` / `setLayerVisible(...)`** on the
|
|
70
|
+
viewer surface and the element, for an app that wants to frame the view,
|
|
71
|
+
place a ruler or drive layer visibility itself. Thin pass-throughs over
|
|
72
|
+
behavior that already existed internally; `getLayers()` is also the only way
|
|
73
|
+
to read a layer's name, group, colors and shape counts.
|
|
74
|
+
|
|
10
75
|
## [1.2.0] - 2026-09-03
|
|
11
76
|
|
|
12
77
|
### Added
|
package/README.md
CHANGED
|
@@ -65,6 +65,14 @@ a streaming WebAssembly compile — see
|
|
|
65
65
|
and ASCII DRC results.
|
|
66
66
|
- **Navigates hierarchy**. You can search cells and labels, and measure
|
|
67
67
|
distances.
|
|
68
|
+
- **Shows gdsfactory / kfactory ports**. A layout written by gdsfactory 8+
|
|
69
|
+
carries its ports as KLayout metadata inside the file; the viewer reads them
|
|
70
|
+
back, draws every port as a bar across its width with an arrow the way it
|
|
71
|
+
faces (and its name, close in), and lists the top cell's ports in the panel.
|
|
72
|
+
No Python involved.
|
|
73
|
+
- **Compares two layouts**. One viewer can hold two of them, drawn through one
|
|
74
|
+
camera, with a crossfade between them and a per-layer highlight of where they
|
|
75
|
+
differ. See [Two layouts in one viewer](docs/embedding.md#two-layouts-in-one-viewer).
|
|
68
76
|
|
|
69
77
|
## Installation
|
|
70
78
|
|
|
@@ -91,8 +99,6 @@ takes one attribute and exposes a handful of methods.
|
|
|
91
99
|
|
|
92
100
|
#### Attributes
|
|
93
101
|
|
|
94
|
-
The element takes one attribute:
|
|
95
|
-
|
|
96
102
|
| Attribute | Description |
|
|
97
103
|
|---|---|
|
|
98
104
|
| `src` | URL of a layout to fetch and display. Setting it later reloads. |
|
|
@@ -104,26 +110,35 @@ The element exposes the following members:
|
|
|
104
110
|
| Member | Returns | Description |
|
|
105
111
|
|---|---|---|
|
|
106
112
|
| `ready` | `Promise<ViewerSurface>` | Resolves once the engine has mounted. Every method in the following table awaits this, so you rarely need it directly. |
|
|
107
|
-
| `load(source, options?)` | `Promise<void>` | `source` is a URL string, a `Uint8Array`, or an `ArrayBuffer`. `options.reload` keeps the current camera and layer visibility instead of framing the design. Resolves once the layout is on screen; rejects on a failed fetch, a file the parser refuses, or — with an error named `AbortError` — when a later load superseded this one. |
|
|
113
|
+
| `load(source, options?)` | `Promise<void>` | `source` is a URL string, a `Uint8Array`, or an `ArrayBuffer`. `options.reload` keeps the current camera and layer visibility instead of framing the design. `options.slot` is `"a"` (the default) or `"b"`, which loads a second layout alongside the first to compare them — see [Two layouts in one viewer](docs/embedding.md#two-layouts-in-one-viewer). Resolves once the layout is on screen; rejects on a failed fetch, a file the parser refuses, or — with an error named `AbortError` — when a later load into the same slot superseded this one. |
|
|
108
114
|
| `showLoading(label?)` | `Promise<void>` | Shows the loading overlay, for the wait before a `load()` of bytes the page is fetching itself. `load(url)` does this on its own. |
|
|
109
115
|
| `goToPoint(x, y)` | `Promise<boolean>` | Centers on a coordinate in microns and flashes a crosshair. Resolves `true` if the point is inside the layout. |
|
|
110
116
|
| `setLyp(name, text)` | `Promise<void>` | Applies a `.lyp` layer-properties file. Pass `""` to clear. |
|
|
111
117
|
| `setMarkers(name, text)` | `Promise<void>` | Applies a marker database. The viewer detects the format from the content. |
|
|
112
118
|
| `showError(message)` | `Promise<void>` | Replaces the view with an error message. |
|
|
113
119
|
| `destroy()` | `Promise<void>` | Releases the viewer's WebAssembly instance and WebGL context for good. Rarely needed — see [Removal parks the viewer](#removal-parks-the-viewer). |
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
120
|
+
| `getCamera()` | `Promise<{zoom, panX, panY}>` | The current pan/zoom. |
|
|
121
|
+
| `setCamera(camera)` | `Promise<void>` | Sets the pan/zoom. Clamped to the loaded design's bounds (the union of both, with two layouts loaded). |
|
|
122
|
+
| `getLayers()` | `Promise<LayerInfo[]>` | Every layer's name, group, colors, visibility and shape counts, plus the `source` slot it came from. |
|
|
123
|
+
| `setLayerVisible(layer, datatype, visible)` | `Promise<void>` | Shows or hides one layer. |
|
|
124
|
+
| `getMeasurements()` | `Promise<{x0,y0,x1,y1}[]>` | Every ruler on screen, in micron endpoints. |
|
|
125
|
+
| `addMeasurement(x0, y0, x1, y1)` | `Promise<void>` | Places a finished ruler without disturbing measure mode. |
|
|
126
|
+
| `clearMeasurements()` | `Promise<void>` | Removes every ruler. Rulers don't survive a reload either way. |
|
|
127
|
+
| `unload(slot?)` | `Promise<void>` | Drops the second layout, leaving a single-layout viewer. |
|
|
128
|
+
| `setBlend(t)` | `Promise<void>` | Crossfades two loaded layouts: `0` shows only A, `1` only B, between overlays them. |
|
|
129
|
+
| `getBlend()` | `Promise<number>` | The current crossfade. |
|
|
130
|
+
|
|
131
|
+
Every `load()` cancels the one before it *for the same slot*, so two quick
|
|
132
|
+
changes to `src` show the second layout even when the first is the slower
|
|
133
|
+
download.
|
|
117
134
|
|
|
118
135
|
#### Events
|
|
119
136
|
|
|
120
|
-
The element dispatches
|
|
121
|
-
— the `src` attribute, `load()`, or a host pushing bytes through its surface.
|
|
122
|
-
Neither bubbles.
|
|
137
|
+
The element dispatches events on itself. None bubbles.
|
|
123
138
|
|
|
124
139
|
| Event | `detail` | When |
|
|
125
140
|
|---|---|---|
|
|
126
|
-
| `gds-load` | `{ layerCount, cellCount }` | A layout finished loading and is on screen. |
|
|
141
|
+
| `gds-load` | `{ slot, layerCount, cellCount, portCount }` | A layout finished loading and is on screen, whichever way the load was started — the `src` attribute, `load()`, or a host pushing bytes through its surface. `slot` is which of the two layouts it is. `portCount` is how many ports its kfactory metadata declared, 0 for a plain file. |
|
|
127
142
|
| `gds-error` | `{ message }` | A load failed, or `showError()` was called. `message` is the text the viewer shows. |
|
|
128
143
|
|
|
129
144
|
```js
|