@wafertools/wafermap 0.21.1 → 0.23.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 (50) hide show
  1. package/AGENTS.md +181 -0
  2. package/CHANGELOG.md +261 -1
  3. package/README.md +9 -1
  4. package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
  5. package/dist/packages/canvas-adapter/charts/scatter.js +1 -1
  6. package/dist/packages/canvas-adapter/dieList.d.ts +41 -0
  7. package/dist/packages/canvas-adapter/dieList.js +2 -0
  8. package/dist/packages/canvas-adapter/icons.js +1 -1
  9. package/dist/packages/canvas-adapter/index.d.ts +4 -0
  10. package/dist/packages/canvas-adapter/index.js +1 -1
  11. package/dist/packages/canvas-adapter/maplessSummary.d.ts +34 -0
  12. package/dist/packages/canvas-adapter/maplessSummary.js +1 -0
  13. package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +9 -11
  14. package/dist/packages/canvas-adapter/renderWaferGallery.js +8 -8
  15. package/dist/packages/canvas-adapter/renderWaferMap.d.ts +31 -1
  16. package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
  17. package/dist/packages/canvas-adapter/summaryPanel.d.ts +13 -1
  18. package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
  19. package/dist/packages/canvas-adapter/toolbar.d.ts +4 -1
  20. package/dist/packages/canvas-adapter/toolbar.js +1 -1
  21. package/dist/packages/canvas-adapter/userGuideHtml.d.ts +1 -1
  22. package/dist/packages/canvas-adapter/userGuideHtml.js +59 -22
  23. package/dist/packages/canvas-adapter/version.d.ts +2 -2
  24. package/dist/packages/canvas-adapter/version.js +1 -1
  25. package/dist/packages/canvas-adapter/warnings.d.ts +57 -0
  26. package/dist/packages/canvas-adapter/warnings.js +1 -0
  27. package/dist/packages/core/classify.d.ts +6 -2
  28. package/dist/packages/core/dies.d.ts +67 -7
  29. package/dist/packages/core/dies.js +1 -1
  30. package/dist/packages/core/probe.d.ts +5 -0
  31. package/dist/packages/core/probe.js +1 -1
  32. package/dist/packages/core/transforms.d.ts +4 -4
  33. package/dist/packages/core/transforms.js +1 -1
  34. package/dist/packages/renderer/buildView.d.ts +3 -3
  35. package/dist/packages/renderer/buildView.js +1 -1
  36. package/dist/packages/renderer/buildWaferMap.d.ts +40 -9
  37. package/dist/packages/renderer/buildWaferMap.js +1 -1
  38. package/dist/packages/renderer/index.d.ts +1 -1
  39. package/dist/packages/renderer/index.js +1 -1
  40. package/dist/packages/stats/analyzeWaferLot.js +1 -1
  41. package/dist/packages/stats/analyzeWaferMap.js +1 -1
  42. package/dist/packages/stats/clusterDetection.d.ts +2 -2
  43. package/dist/packages/stats/patternClassification.d.ts +2 -2
  44. package/dist/packages/stats/regions.d.ts +6 -6
  45. package/dist/packages/stats/regions.js +1 -1
  46. package/dist/packages/stats/renderFindingsReport.js +15 -15
  47. package/dist/packages/stats/renderSummaryReport.js +17 -17
  48. package/dist/packages/stats/types.d.ts +34 -4
  49. package/llms.txt +39 -0
  50. package/package.json +12 -8
@@ -63,7 +63,7 @@ export const USER_GUIDE_HTML=`<div class="wmap-guide">
63
63
  .wmap-guide-online-link{display:none!important}
64
64
  }
65
65
  </style>
66
- <h1 id="wafer-map-user-guide">Wafer Map \u2014 User Guide<span class="wmap-guide-version" title="Built 2026-08-01T11:07:57.852Z">v0.21.1</span></h1>
66
+ <h1 id="wafer-map-user-guide">Wafer Map \u2014 User Guide<span class="wmap-guide-version" title="Built 2026-08-16T17:09:32.912Z">v0.23.0</span></h1>
67
67
  <p class="wmap-guide-online-link">This is a quick reference. <a href="https://wafertools.github.io/wafermap/user-guide/" target="_blank" rel="noopener">View the full illustrated guide online \u2197</a></p>
68
68
  <p>This guide describes the display and analysis features of the wafer map viewer.
69
69
  It is written for users who may be semiconductor test engineers, device engineers, and yield engineers
@@ -219,7 +219,7 @@ verdicts, as an alternative to spec-limit judgement.</p>
219
219
  <p>The toolbar sits at the top-right of the map and is always visible. Controls that
220
220
  are not applicable to the current mode are hidden automatically. (Hovering the map
221
221
  shows die tooltips \u2014 a separate thing from the toolbar, which is always present.)</p>
222
- <p><img src="data:image/png;base64,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" alt="Single-map toolbar"></p>
222
+ <p><img src="data:image/png;base64,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" alt="Single-map toolbar"></p>
223
223
  <h3 id="single-map">Single map</h3>
224
224
  <table>
225
225
  <thead>
@@ -235,11 +235,6 @@ shows die tooltips \u2014 a separate thing from the toolbar, which is always pre
235
235
  <td>Switches the active plot mode (see <a href="#2-plot-modes" onclick="(function(e){e.preventDefault();var g=e.target.closest('.wmap-guide');var el=g&&g.querySelector('[id=\\'2-plot-modes\\']');if(el)el.scrollIntoView({behavior:'smooth'});})(event)">Section 2</a>). When multiple tests are available, a test selector appears alongside it.</td>
236
236
  </tr>
237
237
  <tr>
238
- <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xOCA0SDZsNiA4LTYgOGgxMiIvPjwvc3ZnPgo=" width="20" height="20"></td>
239
- <td>Aggregation method</td>
240
- <td>Stacked modes only. Selects how values from multiple wafers are combined per die position: Mean, Median, Std Dev, Min, Max, or Count.</td>
241
- </tr>
242
- <tr>
243
238
  <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yIDEyczMuNi03IDEwLTcgMTAgNyAxMCA3LTMuNiA3LTEwIDctMTAtNy0xMC03eiIvPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTIiIHI9IjMiLz48L3N2Zz4K" width="20" height="20"></td>
244
239
  <td>Overlays</td>
245
240
  <td>Check-menu of optional display layers: XY axis indicator, ring boundaries, quadrant lines, die coordinate labels, reticle grid (when geometry is configured), Spec pass/fail (Test Value mode with limits), and Test pass/fail (Test Value mode, active test is functional or has recorded verdicts).</td>
@@ -255,24 +250,19 @@ shows die tooltips \u2014 a separate thing from the toolbar, which is always pre
255
250
  <td>Test Value and Stacked Test Values modes only. Applies a log\u2081\u2080 scale to the colour mapping. Only active when all displayed values are positive. Hidden whenever a pass/fail display is active or the active test is functional.</td>
256
251
  </tr>
257
252
  <tr>
253
+ <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik01IDQgTDUgMjAiLz48cGF0aCBkPSJNNSA0IEw4IDQiLz48cGF0aCBkPSJNNSAyMCBMOCAyMCIvPjxwYXRoIGQ9Ik0xOSA0IEwxOSAyMCIvPjxwYXRoIGQ9Ik0xOSA0IEwxNiA0Ii8+PHBhdGggZD0iTTE5IDIwIEwxNiAyMCIvPjxwYXRoIGQ9Ik01IDEyIEwxOSAxMiIgc3Ryb2tlLWRhc2hhcnJheT0iMyAyIi8+PC9zdmc+Cg==" width="20" height="20"></td>
254
+ <td>Colorbar range</td>
255
+ <td>Test Value mode with spec limits only. Toggles the colorbar between the <strong>spec-limit range</strong> (default \u2014 the colours mean the same thing on every wafer, so maps are comparable) and the <strong>data range</strong> (stretches the scale to the values actually present, which shows more contrast but is not comparable between wafers).</td>
256
+ </tr>
257
+ <tr>
258
258
  <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjciIHg9IjMiIHk9IjMiIHJ4PSIxIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iNyIgeD0iMyIgeT0iMTQiIHJ4PSIxIi8+PHBhdGggZD0iTTE0IDRoNyIvPjxwYXRoIGQ9Ik0xNCA5aDciLz48cGF0aCBkPSJNMTQgMTVoNyIvPjxwYXRoIGQ9Ik0xNCAyMGg3Ii8+PC9zdmc+Cg==" width="20" height="20"></td>
259
259
  <td>Legend style</td>
260
260
  <td>Bin modes only. Controls where the bin legend is positioned relative to the map: Default (right), Compact, Left, Top, Bottom, or Floating.</td>
261
261
  </tr>
262
262
  <tr>
263
- <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMSAxMmE5IDkgMCAxIDEtOS05YzIuNTIgMCA0LjkzIDEgNi43NCAyLjc0TDIxIDgiLz48cGF0aCBkPSJNMjEgM3Y1aC01Ii8+PC9zdmc+Cg==" width="20" height="20"></td>
264
- <td>Rotate 90\xB0</td>
265
- <td>Rotates the display 90\xB0 clockwise. Applies cumulatively. Die coordinates are unaffected.</td>
266
- </tr>
267
- <tr>
268
- <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Im0zIDcgNSA1LTUgNVY3Ii8+PHBhdGggZD0ibTIxIDctNSA1IDUgNVY3Ii8+PHBhdGggZD0iTTEyIDIwdjIiLz48cGF0aCBkPSJNMTIgMTR2MiIvPjxwYXRoIGQ9Ik0xMiA4djIiLz48cGF0aCBkPSJNMTIgMnYyIi8+PC9zdmc+Cg==" width="20" height="20"></td>
269
- <td>Flip horizontal</td>
270
- <td>Mirrors the display left/right. Die coordinates are unaffected.</td>
271
- </tr>
272
- <tr>
273
- <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Im0xNyAzLTUgNS01LTVoMTAiLz48cGF0aCBkPSJtMTcgMjEtNS01LTUgNWgxMCIvPjxwYXRoIGQ9Ik00IDEySDIiLz48cGF0aCBkPSJNMTAgMTJIOCIvPjxwYXRoIGQ9Ik0xNiAxMmgtMiIvPjxwYXRoIGQ9Ik0yMiAxMmgtMiIvPjwvc3ZnPgo=" width="20" height="20"></td>
274
- <td>Flip vertical</td>
275
- <td>Mirrors the display top/bottom. Die coordinates are unaffected.</td>
263
+ <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTIiIHI9IjEwIi8+PHBvbHlnb24gcG9pbnRzPSIxNi4yNCA3Ljc2IDE0LjEyIDE0LjEyIDcuNzYgMTYuMjQgOS44OCA5Ljg4IDE2LjI0IDcuNzYiIGZpbGw9IiMzNzQxNTEiIHN0cm9rZT0ibm9uZSIvPjwvc3ZnPgo=" width="20" height="20"></td>
264
+ <td>Orientation</td>
265
+ <td>Menu of display transforms: <strong>Rotate 90\xB0 clockwise</strong> (applies cumulatively), <strong>Flip horizontal</strong>, <strong>Flip vertical</strong>. These change only how the wafer is drawn \u2014 die coordinates in tooltips and labels are always the original values, whatever the orientation.</td>
276
266
  </tr>
277
267
  <tr>
278
268
  <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Im0xMyAxMy41IDItMi41LTItMi41Ii8+PHBhdGggZD0ibTIxIDIxLTQuMy00LjMiLz48cGF0aCBkPSJNOSA4LjUgNyAxMWwyIDIuNSIvPjxjaXJjbGUgY3g9IjExIiBjeT0iMTEiIHI9IjgiLz48L3N2Zz4K" width="20" height="20"></td>
@@ -325,6 +315,11 @@ shows die tooltips \u2014 a separate thing from the toolbar, which is always pre
325
315
  <td>Opens or closes the Findings sidebar (see <a href="#6-findings-sidebar" onclick="(function(e){e.preventDefault();var g=e.target.closest('.wmap-guide');var el=g&&g.querySelector('[id=\\'6-findings-sidebar\\']');if(el)el.scrollIntoView({behavior:'smooth'});})(event)">Section 6</a>).</td>
326
316
  </tr>
327
317
  <tr>
318
+ <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMTAuMjkgMy44NiAxLjgyIDE4YTIgMiAwIDAgMCAxLjcxIDNoMTYuOTRhMiAyIDAgMCAwIDEuNzEtM0wxMy43MSAzLjg2YTIgMiAwIDAgMC0zLjQyIDB6Ii8+PHBhdGggZD0iTTEyIDl2NCIvPjxwYXRoIGQ9Ik0xMiAxN2guMDEiLz48L3N2Zz4K" width="20" height="20"></td>
319
+ <td>Data warnings</td>
320
+ <td>Appears <strong>only when there is something to report</strong> about the data behind the map. Click it for the details. A red \u26D4 means the map may be positionally wrong \u2014 usually that wafer geometry was guessed rather than supplied, so dies may not sit where they appear to. An amber \u26A0 means something expected is missing or was skipped, but what is drawn is correct.</td>
321
+ </tr>
322
+ <tr>
328
323
  <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIvPjxwYXRoIGQ9Ik05LjA5IDlhMyAzIDAgMCAxIDUuODMgMWMwIDItMyAzLTMgMyIvPjxwYXRoIGQ9Ik0xMiAxN2guMDEiLz48L3N2Zz4K" width="20" height="20"></td>
329
324
  <td>User guide</td>
330
325
  <td>Opens this guide.</td>
@@ -432,11 +427,31 @@ failure category across the wafer.</p>
432
427
  <td>Sets the number of columns in the card grid.</td>
433
428
  </tr>
434
429
  <tr>
435
- <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xMy45OTcgNGEyIDIgMCAwIDEgMS43NiAxLjA1bC40ODYuOUEyIDIgMCAwIDAgMTguMDAzIDdIMjBhMiAyIDAgMCAxIDIgMnY5YTIgMiAwIDAgMS0yIDJINGEyIDIgMCAwIDEtMi0yVjlhMiAyIDAgMCAxIDItMmgxLjk5N2EyIDIgMCAwIDAgMS43NTktMS4wNDhsLjQ4OS0uOTA0QTIgMiAwIDAgMSAxMC4wMDQgNHoiLz48Y2lyY2xlIGN4PSIxMiIgY3k9IjEzIiByPSIzIi8+PC9zdmc+Cg==" width="20" height="20"></td>
430
+ <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xMy45OTcgNGEyIDIgMCAwIDEgMS43NiAxLjA1bC40ODYuOUEyIDIgMCAwIDAgMTguMDAzIDdIMjBhMiAyIDAgMCAxIDIgMnY5YTIgMiAwIDAgMS0yIDJINGEyIDIgMCAwIDEtMi0yVjlhMiAyIDAgMCAxIDItMmgxLjk5N2EyIDIgMCAwIDAgMS43NTktMS4wNDhsLjQ4OS0uOTA0QTIgMiAwIDAgMSAxMC4wMDQgNHoiLz48Y2lyY2xlIGN4PSIxMiIgY3k9IjEzIiByPSIzIi8+PGNpcmNsZSBjeD0iNS41IiBjeT0iNC41IiByPSIwLjgiIGZpbGw9IiMzNzQxNTEiIHN0cm9rZT0ibm9uZSIvPjxjaXJjbGUgY3g9IjgiIGN5PSI0LjUiIHI9IjAuOCIgZmlsbD0iIzM3NDE1MSIgc3Ryb2tlPSJub25lIi8+PGNpcmNsZSBjeD0iNS41IiBjeT0iNyIgcj0iMC44IiBmaWxsPSIjMzc0MTUxIiBzdHJva2U9Im5vbmUiLz48Y2lyY2xlIGN4PSI4IiBjeT0iNyIgcj0iMC44IiBmaWxsPSIjMzc0MTUxIiBzdHJva2U9Im5vbmUiLz48L3N2Zz4K" width="20" height="20"></td>
436
431
  <td>Save image</td>
437
432
  <td>Downloads the full gallery grid as a single PNG.</td>
438
433
  </tr>
439
434
  <tr>
435
+ <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xOCA0SDZsNiA4LTYgOGgxMiIvPjwvc3ZnPgo=" width="20" height="20"></td>
436
+ <td>Aggregation method</td>
437
+ <td>Stacked modes only. Selects how values from multiple wafers are combined per die position: Mean, Median, Std Dev, Min, Max, or Count.</td>
438
+ </tr>
439
+ <tr>
440
+ <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik01IDIxIEw1IDMiLz48cGF0aCBkPSJNMy41IDUgTDUgMyBMNi41IDUiLz48cGF0aCBkPSJNNSAyMSBMMjEgMjEiLz48cGF0aCBkPSJNMTkgMTkuNSBMMjEgMjEgTDE5IDIyLjUiLz48cGF0aCBkPSJNNiAyMCBDIDYgMTIsIDEwIDcsIDIwIDYiLz48L3N2Zz4K" width="20" height="20"></td>
441
+ <td>Log scale</td>
442
+ <td>Test Value and Stacked Test Values modes only. Applies a log\u2081\u2080 scale to the colour mapping for all cards.</td>
443
+ </tr>
444
+ <tr>
445
+ <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjciIHg9IjMiIHk9IjMiIHJ4PSIxIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iNyIgeD0iMyIgeT0iMTQiIHJ4PSIxIi8+PHBhdGggZD0iTTE0IDRoNyIvPjxwYXRoIGQ9Ik0xNCA5aDciLz48cGF0aCBkPSJNMTQgMTVoNyIvPjxwYXRoIGQ9Ik0xNCAyMGg3Ii8+PC9zdmc+Cg==" width="20" height="20"></td>
446
+ <td>Legend style</td>
447
+ <td>Bin modes only. Sets where the bin legend sits relative to each card.</td>
448
+ </tr>
449
+ <tr>
450
+ <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMS44IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik01IDQgTDUgMjAiLz48cGF0aCBkPSJNNSA0IEw4IDQiLz48cGF0aCBkPSJNNSAyMCBMOCAyMCIvPjxwYXRoIGQ9Ik0xOSA0IEwxOSAyMCIvPjxwYXRoIGQ9Ik0xOSA0IEwxNiA0Ii8+PHBhdGggZD0iTTE5IDIwIEwxNiAyMCIvPjxwYXRoIGQ9Ik01IDEyIEwxOSAxMiIgc3Ryb2tlLWRhc2hhcnJheT0iMyAyIi8+PC9zdmc+Cg==" width="20" height="20"></td>
451
+ <td>Colorbar range</td>
452
+ <td>Test Value mode with spec limits only. Toggles all cards between the spec-limit range and the data range. Leave it on spec limits when comparing wafers \u2014 the data range rescales per view.</td>
453
+ </tr>
454
+ <tr>
440
455
  <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNOCAydjQiLz48cGF0aCBkPSJNMTIgMnY0Ii8+PHBhdGggZD0iTTE2IDJ2NCIvPjxyZWN0IHdpZHRoPSIxNiIgaGVpZ2h0PSIxOCIgeD0iNCIgeT0iNCIgcng9IjIiLz48cGF0aCBkPSJNOCAxMGg2Ii8+PHBhdGggZD0iTTggMTRoOCIvPjxwYXRoIGQ9Ik04IDE4aDUiLz48L3N2Zz4K" width="20" height="20"></td>
441
456
  <td>Findings</td>
442
457
  <td>Opens or closes the lot-level Findings sidebar.</td>
@@ -446,6 +461,16 @@ failure category across the wafer.</p>
446
461
  <td>Insights</td>
447
462
  <td>Swaps the grid for a lot-wide chart suite \u2014 yield, bin breakdown, process capability, and more (see <a href="#8-insights-tab" onclick="(function(e){e.preventDefault();var g=e.target.closest('.wmap-guide');var el=g&&g.querySelector('[id=\\'8-insights-tab\\']');if(el)el.scrollIntoView({behavior:'smooth'});})(event)">Section 8</a>). Only shown when the application has enabled it.</td>
448
463
  </tr>
464
+ <tr>
465
+ <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMTAuMjkgMy44NiAxLjgyIDE4YTIgMiAwIDAgMCAxLjcxIDNoMTYuOTRhMiAyIDAgMCAwIDEuNzEtM0wxMy43MSAzLjg2YTIgMiAwIDAgMC0zLjQyIDB6Ii8+PHBhdGggZD0iTTEyIDl2NCIvPjxwYXRoIGQ9Ik0xMiAxN2guMDEiLz48L3N2Zz4K" width="20" height="20"></td>
466
+ <td>Data warnings</td>
467
+ <td>Appears only when something is worth reporting about the lot. Collected across every wafer and de-duplicated, so a problem affecting the whole lot is stated once rather than repeated per card.</td>
468
+ </tr>
469
+ <tr>
470
+ <td><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNzQxNTEiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIvPjxwYXRoIGQ9Ik05LjA5IDlhMyAzIDAgMCAxIDUuODMgMWMwIDItMyAzLTMgMyIvPjxwYXRoIGQ9Ik0xMiAxN2guMDEiLz48L3N2Zz4K" width="20" height="20"></td>
471
+ <td>User guide</td>
472
+ <td>Opens this guide.</td>
473
+ </tr>
449
474
  </tbody></table>
450
475
  <p>Click a card&#39;s expand button to detach it into its own separate window with the
451
476
  complete single-map toolbar (falls back to a floating window inside the page if
@@ -559,8 +584,20 @@ doesn&#39;t need the map on screen the way a finding&#39;s highlight does.</p>
559
584
  <p>A <strong>Summary report</strong> button (when present) opens a printable full-detail
560
585
  report in a new window or tab, still covering everything findings-adjacent \u2014
561
586
  yield, bin breakdown, ring and quadrant statistics, per-test statistics, and
562
- the full findings list \u2014 and can be saved as a PDF from your browser&#39;s print
587
+ the findings list \u2014 and can be saved as a PDF from your browser&#39;s print
563
588
  dialog.</p>
589
+ <h3 id="why-some-findings-name-two-bins">Why some findings name two bins</h3>
590
+ <p>A finding may read <strong>&quot;hard bin 3 and soft bin 3 (same dies)&quot;</strong>. That is one
591
+ group of dies counted in two bin spaces, not two separate groups added together.
592
+ Hard and soft bins are independent numbering systems, so this wording appears
593
+ only when the two happen to cover exactly the same dies \u2014 reporting it twice
594
+ would look like two independent problems.</p>
595
+ <p>For the same reason, when a single pass bin is configured you will see the
596
+ <strong>yield</strong> finding for a region but not a separate finding for the pass bin
597
+ itself: &quot;pass-bin occurrence is 22 points lower&quot; and &quot;yield is 22 points lower&quot;
598
+ are the same sentence.</p>
599
+ <p>Nothing is discarded \u2014 an application reading the findings programmatically
600
+ still receives every one of them.</p>
564
601
  <p>For <strong>lot-level views</strong> (gallery), the sidebar shows lot-level findings by
565
602
  default, with a <strong>Wafers</strong> tab listing every wafer that has its own per-wafer
566
603
  findings \u2014 click a row to open that wafer.</p>
@@ -1,3 +1,3 @@
1
- export declare const WMAP_VERSION = "0.21.1";
2
- export declare const WMAP_BUILD_TIME = "2026-08-01T11:07:58.032Z";
1
+ export declare const WMAP_VERSION = "0.23.0";
2
+ export declare const WMAP_BUILD_TIME = "2026-08-16T17:37:48.778Z";
3
3
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- export const WMAP_VERSION="0.21.1",WMAP_BUILD_TIME="2026-08-01T11:07:58.032Z";
1
+ export const WMAP_VERSION="0.23.0",WMAP_BUILD_TIME="2026-08-16T17:37:48.778Z";
@@ -0,0 +1,57 @@
1
+ import type { WaferWarning, WaferMapResult } from '../renderer/buildWaferMap.js';
2
+ import type { StatsSummary, LotStatsSummary } from '../stats/types.js';
3
+ export type { WaferWarning };
4
+ /**
5
+ * Controls the built-in warning UI.
6
+ *
7
+ * Hosts that already have their own notification system should set
8
+ * `display: false` and read the warnings from `onWarning` — that way the library
9
+ * still does the collecting, de-duplicating and severity ordering, and the host
10
+ * only owns presentation. Turning the UI off without wiring `onWarning` means
11
+ * nobody is told, which is the situation this feature exists to end.
12
+ */
13
+ export interface WarningsOptions {
14
+ /**
15
+ * Show the built-in warning indicator in the toolbar and the banner in the
16
+ * Summary panel. Default `true`.
17
+ */
18
+ display?: boolean;
19
+ /**
20
+ * Called with the collected, de-duplicated, severity-ordered warnings whenever
21
+ * they change (including once on mount, with an empty array when there are
22
+ * none, so a host can clear its own display).
23
+ */
24
+ onWarning?: (warnings: WaferWarning[]) => void;
25
+ }
26
+ /** Severity with the documented default applied. */
27
+ export declare function severityOf(w: WaferWarning): NonNullable<WaferWarning['severity']>;
28
+ /**
29
+ * Gather every advisory relevant to one rendered map, most serious first.
30
+ *
31
+ * De-duplicated on `code` + `message`: a lot gallery legitimately produces the
32
+ * same geometry advisory on many wafers, and repeating it once per wafer would
33
+ * bury the one that differs.
34
+ */
35
+ export declare function collectWarnings(sources: {
36
+ /** `warnings` is optional, not merely the object: a gallery card is a
37
+ * `WaferMapDisplayItem`, which carries the field only when it was spread
38
+ * from a `WaferMapResult`. The body already tolerates its absence — the
39
+ * type used to require it, which is why callers reached this through a
40
+ * cast. */
41
+ result?: Partial<Pick<WaferMapResult, 'warnings'>> | null;
42
+ statsSummary?: StatsSummary | null;
43
+ lotStatsSummary?: LotStatsSummary | null;
44
+ }): WaferWarning[];
45
+ /**
46
+ * The Summary panel banner. One block per severity present, so an "dies may be
47
+ * mis-positioned" error is never visually flattened into an advisory.
48
+ */
49
+ export declare function buildWarningsBanner(warnings: WaferWarning[]): HTMLDivElement;
50
+ /**
51
+ * The popup opened by the toolbar's warning indicator.
52
+ *
53
+ * Anchored like the toolbar's other menus (see `buildCheckMenuEl`) and flips to
54
+ * right-aligned near the viewport edge.
55
+ */
56
+ export declare function buildWarningsMenuEl(anchorRect: DOMRect, warnings: WaferWarning[], ownerWindow?: Window): HTMLDivElement;
57
+ //# sourceMappingURL=warnings.d.ts.map
@@ -0,0 +1 @@
1
+ import{CLR as r,Z_BASE as y}from"./toolbar.js";const f={error:0,warning:1,info:2};export function severityOf(e){return e.severity??"warning"}export function collectWarnings(e){const i=[],s=new Set,n=t=>{if(!t?.message)return;const o=`${t.code}\0${t.message}`;s.has(o)||(s.add(o),i.push(t))};for(const t of e.result?.warnings??[])n(t);for(const t of e.statsSummary?.stats.warnings??[])n(t);for(const t of e.lotStatsSummary?.perWafer??[])for(const o of t.summary.stats.warnings??[])n(o);return i.sort((t,o)=>f[severityOf(t)]-f[severityOf(o)])}function b(e){return e==="error"?{bg:r.errBg,border:r.errBorder,text:r.errText}:{bg:r.warnBg,border:r.warnBorder,text:r.warnText}}function h(e){return e==="error"?"\u26D4":e==="info"?"\u2139":"\u26A0"}export function buildWarningsBanner(e){const i=document.createElement("div");Object.assign(i.style,{marginBottom:"10px"});for(const s of e){const n=severityOf(s),t=b(n),o=document.createElement("div");Object.assign(o.style,{background:t.bg,border:`1px solid ${t.border}`,borderRadius:"4px",padding:"7px 9px",marginBottom:"6px",fontSize:"10px",color:t.text,lineHeight:"1.5"}),o.setAttribute("role","status"),o.textContent=`${h(n)} ${s.message}`,i.appendChild(o)}return i}export function buildWarningsMenuEl(e,i,s=window){const n=document.createElement("div"),t=280,w=e.left+t<=(s.innerWidth??1/0)?e.left:Math.max(4,e.right-t);Object.assign(n.style,{position:"fixed",top:`${e.bottom+4}px`,left:`${w}px`,background:r.menuBg,border:`1px solid ${r.menuBorder}`,borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",zIndex:y,width:`${t}px`,maxHeight:"320px",overflowY:"auto",padding:"4px 0",pointerEvents:"auto"}),n.setAttribute("role","dialog"),n.setAttribute("aria-label","Data warnings");const d=document.createElement("div");Object.assign(d.style,{padding:"6px 12px 4px",fontSize:"10px",fontWeight:"700",letterSpacing:"0.06em",textTransform:"uppercase",color:r.label}),d.textContent=i.length===1?"1 warning":`${i.length} warnings`,n.appendChild(d);for(const c of i){const x=severityOf(c),m=b(x),a=document.createElement("div");Object.assign(a.style,{display:"flex",gap:"8px",padding:"8px 12px",fontSize:"11px",lineHeight:"1.5",color:r.text,borderTop:`1px solid ${r.menuBorder}`,alignItems:"flex-start"});const p=document.createElement("span");Object.assign(p.style,{color:m.text,flexShrink:"0"}),p.textContent=h(x),a.appendChild(p);const l=document.createElement("div"),g=document.createElement("div");Object.assign(g.style,{fontWeight:"700",color:m.text,marginBottom:"2px"}),g.textContent=c.code,l.appendChild(g);const u=document.createElement("div");u.textContent=c.message,l.appendChild(u),a.appendChild(l),n.appendChild(a)}return n}
@@ -1,5 +1,5 @@
1
1
  import type { Wafer } from './wafer.js';
2
- import type { Die } from './dies.js';
2
+ import type { PositionedDie } from './dies.js';
3
3
  export type Quadrant = 'NE' | 'NW' | 'SW' | 'SE';
4
4
  export interface DieClassification {
5
5
  ring: number;
@@ -17,8 +17,12 @@ export interface ClassifyOptions {
17
17
  * to its notch, so they must follow orientation and stay invariant to how the user
18
18
  * has rotated the on-screen view. (Not "screen" coordinates — those are post-
19
19
  * interactive-transform and live only in the renderer.)
20
+ *
21
+ * Takes a `PositionedDie`, not `Die` — callers must filter to `hasPosition`
22
+ * first (region builders only ever classify positioned dies; an unpositioned
23
+ * die has no ring/quadrant by definition).
20
24
  */
21
- export declare function classifyDie(die: Die, wafer: Wafer, options?: ClassifyOptions): DieClassification;
25
+ export declare function classifyDie(die: PositionedDie, wafer: Wafer, options?: ClassifyOptions): DieClassification;
22
26
  /** Human-readable label for a ring index (1-based) given a total ring count. */
23
27
  export declare function getRingLabel(ring: number, ringCount: number): string;
24
28
  //# sourceMappingURL=classify.d.ts.map
@@ -11,10 +11,19 @@ export interface DieSpec {
11
11
  }
12
12
  export interface Die {
13
13
  id: string;
14
- x: number;
15
- y: number;
16
- physX: number;
17
- physY: number;
14
+ /**
15
+ * Grid position. Absent (together with `y`/`physX`/`physY`) means this die
16
+ * has no reported spatial position at all — it still carries real
17
+ * measured data (`testValues`, `hbin`, …) and counts toward every
18
+ * non-spatial stat, but is never placed on a wafer map/gallery canvas and
19
+ * never enters ring/quadrant/sector/reticle/cluster/pattern analysis. Use
20
+ * `hasPosition()` rather than checking `x`/`y` individually — a die is
21
+ * either fully positioned or fully unpositioned, never half.
22
+ */
23
+ x?: number;
24
+ y?: number;
25
+ physX?: number;
26
+ physY?: number;
18
27
  width: number;
19
28
  height: number;
20
29
  /**
@@ -65,7 +74,52 @@ export interface DieEligibilityOptions {
65
74
  * silently drift apart. Both now call this.
66
75
  */
67
76
  /**
68
- * Return a stable string key for a die — guaranteed format `"x,y"`.
77
+ * Whether a die has a reported spatial position. The single source of truth
78
+ * every spatial function (region builders, cluster/pattern detection, the
79
+ * renderer's grid/geometry inference) filters on — never check `x`/`y`
80
+ * individually elsewhere, since a die is either fully positioned or fully
81
+ * unpositioned (`buildWaferMap` rejects the half-state at build time).
82
+ */
83
+ export declare function hasPosition<T extends {
84
+ x?: number | null;
85
+ y?: number | null;
86
+ }>(die: T): die is T & {
87
+ x: number;
88
+ y: number;
89
+ };
90
+ /**
91
+ * A `Die` known to carry a spatial position — every geometry-only function
92
+ * (ring/quadrant classification, probe-sequence spatial sort, cluster/pattern
93
+ * detection) takes this instead of plain `Die`, so the "caller must filter
94
+ * first" invariant is enforced at the type level rather than by convention.
95
+ * Get one via `dies.filter(isPositionedDie)`.
96
+ */
97
+ export type PositionedDie = Die & {
98
+ x: number;
99
+ y: number;
100
+ physX: number;
101
+ physY: number;
102
+ };
103
+ /**
104
+ * `hasPosition` narrowed for a real `Die`, yielding a `PositionedDie` — i.e.
105
+ * `physX`/`physY` are narrowed too, not just `x`/`y`.
106
+ *
107
+ * Both exist because `hasPosition` is also applied to inputs that carry `x`/`y`
108
+ * and no `physX` at all (a raw `DieResult`, before any layout has happened), so
109
+ * it cannot promise the physical pair. Anything working with built `Die`s wants
110
+ * this one: before it existed every such caller wrote
111
+ * `dies.filter(hasPosition) as PositionedDie[]`, asserting this same invariant
112
+ * by hand — six copies of one cast, each a place the type checker had been told
113
+ * to stop looking.
114
+ *
115
+ * The invariant is real, which is why the runtime check need only look at
116
+ * `x`/`y`: a die is either fully positioned or fully unpositioned, never half
117
+ * (`buildWaferMap` rejects the half-state at build time).
118
+ */
119
+ export declare function isPositionedDie<T extends Die>(die: T): die is T & PositionedDie;
120
+ /**
121
+ * Return a stable string key for a die — guaranteed format `"x,y"` for a
122
+ * positioned die, or `"id:<id>"` for an unpositioned one (see `hasPosition`).
69
123
  *
70
124
  * THE way to build a die key. Use it for Map keys and post-enrichment lookups
71
125
  * rather than an ad-hoc template literal: findings carry `dieKeys` in this exact
@@ -74,14 +128,20 @@ export interface DieEligibilityOptions {
74
128
  * it lives in `core/` — `renderer/`, `stats/` and `canvas-adapter/` all need to
75
129
  * agree on one format.
76
130
  *
131
+ * An unpositioned die has no `x`/`y` to key on — every one would collide on
132
+ * the same key without the `id:` fallback, since `id` is the only field
133
+ * guaranteed unique for a die with no position (`buildWaferMap` assigns
134
+ * unpositioned dies an id like `unpositioned_3`).
135
+ *
77
136
  * ```ts
78
137
  * const map = new Map(result.dies.map(d => [getDieKey(d), d]));
79
138
  * const die = map.get(getDieKey({ x: 3, y: -2 }));
80
139
  * ```
81
140
  */
82
141
  export declare function getDieKey(die: {
83
- x: number;
84
- y: number;
142
+ x?: number;
143
+ y?: number;
144
+ id?: string;
85
145
  }): string;
86
146
  export declare function isYieldEligibleDie(die: Die, options?: DieEligibilityOptions): boolean;
87
147
  /**
@@ -1 +1 @@
1
- export function getDieKey(e){return`${e.x},${e.y}`}export function isYieldEligibleDie(e,t={}){return!(!t.includePartial&&e.partial||!t.includeEdgeExcluded&&e.edgeExcluded)}export function generateDies(e,t){const{width:c,height:l,offset:u={x:0,y:0}}=t,n=t.gridSize??Math.ceil(e.radius/Math.min(c,l))+1,s=[];for(let r=-n;r<=n;r++)for(let i=-n;i<=n;i++){const o=e.center.x+i*c+u.x,d=e.center.y+r*l+u.y;s.push({id:`${i}_${r}`,x:i,y:r,physX:o,physY:d,width:c,height:l})}return s}
1
+ export function hasPosition(e){return e.x!=null&&e.y!=null}export function isPositionedDie(e){return e.x!=null&&e.y!=null}export function getDieKey(e){return hasPosition(e)?`${e.x},${e.y}`:`id:${e.id}`}export function isYieldEligibleDie(e,t={}){return!(!t.includePartial&&e.partial||!t.includeEdgeExcluded&&e.edgeExcluded)}export function generateDies(e,t){const{width:u,height:l,offset:o={x:0,y:0}}=t,i=t.gridSize??Math.ceil(e.radius/Math.min(u,l))+1,c=[];for(let n=-i;n<=i;n++)for(let r=-i;r<=i;r++){const s=e.center.x+r*u+o.x,x=e.center.y+n*l+o.y;c.push({id:`${r}_${n}`,x:r,y:n,physX:s,physY:x,width:u,height:l})}return c}
@@ -11,6 +11,11 @@ export interface ProbeSequenceConfig {
11
11
  * snake — alternating direction per row (boustrophedon)
12
12
  * column — top→bottom, left→right
13
13
  * custom — explicit die ID ordering
14
+ *
15
+ * An unpositioned die (see `hasPosition`) has no spatial order to assign for
16
+ * `row`/`column`/`snake` — it's carried through unchanged (no `probeIndex`
17
+ * set), appended after every positioned die. `custom` is unaffected, since
18
+ * it orders by `id`, not position.
14
19
  */
15
20
  export declare function applyProbeSequence(dies: Die[], config: ProbeSequenceConfig): Die[];
16
21
  //# sourceMappingURL=probe.d.ts.map
@@ -1 +1 @@
1
- export function applyProbeSequence(s,i){const{type:p,customOrder:d}=i;if(p==="custom"){if(!d)throw new Error('customOrder is required for type="custom"');const e=new Map(d.map((t,c)=>[t,c])),r=s.map(t=>({...t,probeIndex:e.get(t.id)})),o=r.filter(t=>t.probeIndex===void 0).map(t=>t.id);if(o.length>0)throw new Error(`applyProbeSequence: die IDs not found in customOrder: ${o.join(", ")}`);return r}if(p==="column")return[...s].sort((r,o)=>r.x-o.x||o.y-r.y).map((r,o)=>({...r,probeIndex:o}));const n=new Map;for(const e of s)n.has(e.y)||n.set(e.y,[]),n.get(e.y).push(e);const a=[...n.entries()].sort(([e],[r])=>r-e),u=[];return a.forEach(([,e],r)=>{const o=e.sort((t,c)=>t.x-c.x);u.push(...p==="snake"&&r%2===1?[...o].reverse():o)}),u.map((e,r)=>({...e,probeIndex:r}))}
1
+ import{hasPosition as a}from"./dies.js";export function applyProbeSequence(s,m){const{type:i,customOrder:c}=m;if(i==="custom"){if(!c)throw new Error('customOrder is required for type="custom"');const o=new Map(c.map((t,p)=>[t,p])),e=s.map(t=>({...t,probeIndex:o.get(t.id)})),r=e.filter(t=>t.probeIndex===void 0).map(t=>t.id);if(r.length>0)throw new Error(`applyProbeSequence: die IDs not found in customOrder: ${r.join(", ")}`);return e}const d=s.filter(a),u=s.filter(o=>!a(o));if(i==="column")return[...[...d].sort((e,r)=>e.x-r.x||r.y-e.y).map((e,r)=>({...e,probeIndex:r})),...u];const n=new Map;for(const o of d)n.has(o.y)||n.set(o.y,[]),n.get(o.y).push(o);const x=[...n.entries()].sort(([o],[e])=>e-o),f=[];return x.forEach(([,o],e)=>{const r=o.sort((t,p)=>t.x-p.x);f.push(...i==="snake"&&e%2===1?[...r].reverse():r)}),[...f.map((o,e)=>({...o,probeIndex:e})),...u]}
@@ -1,5 +1,5 @@
1
1
  import type { Wafer } from './wafer.js';
2
- import type { Die, DieSpec } from './dies.js';
2
+ import type { Die, DieSpec, PositionedDie } from './dies.js';
3
3
  export interface DataRow {
4
4
  [key: string]: string | number;
5
5
  }
@@ -120,16 +120,16 @@ export declare function clipDiesToWafer(dies: Die[], wafer: Wafer, dieConfig?: D
120
120
  * Rotate all die display coordinates by wafer.orientation around wafer.center.
121
121
  * Call this after clipping and data mapping so that i/j indices remain intact.
122
122
  */
123
- export declare function applyOrientation(dies: Die[], wafer: Wafer): Die[];
123
+ export declare function applyOrientation(dies: PositionedDie[], wafer: Wafer): PositionedDie[];
124
124
  /**
125
125
  * Apply interactive transforms (rotation + flip) to die display coordinates.
126
126
  * Rotation is around wafer.center; flip mirrors through wafer.center.
127
127
  * Call this at render time — baseDies already have applyOrientation baked in.
128
128
  */
129
- export declare function transformDies(dies: Die[], options: TransformOptions, center?: {
129
+ export declare function transformDies(dies: PositionedDie[], options: TransformOptions, center?: {
130
130
  x: number;
131
131
  y: number;
132
- }): Die[];
132
+ }): PositionedDie[];
133
133
  /**
134
134
  * Attach data values to dies.
135
135
  * matchBy='xy' — matches by wafer coordinates (v0.1 behaviour)
@@ -1 +1 @@
1
- import{getDieKey as u}from"./dies.js";export function rotatePoint(t,n,e,o=0,s=0){const c=e*Math.PI/180,a=Math.cos(c),i=Math.sin(c),f=t-o,r=n-s;return{x:o+f*a+r*i,y:s-f*i+r*a}}export function affineIdentity(){return{a:1,b:0,c:0,d:1,e:0,f:0}}export function affineRotation(t,n=0,e=0){const o=t*Math.PI/180,s=Math.cos(o),c=Math.sin(o);return{a:s,c,b:-c,d:s,e:n-(s*n+c*e),f:e-(-c*n+s*e)}}export function affineMirror(t,n,e=0,o=0){return{a:t?-1:1,c:0,b:0,d:n?-1:1,e:t?2*e:0,f:n?2*o:0}}export function affineCompose(t,n){return{a:t.a*n.a+t.c*n.b,b:t.b*n.a+t.d*n.b,c:t.a*n.c+t.c*n.d,d:t.b*n.c+t.d*n.d,e:t.a*n.e+t.c*n.f+t.e,f:t.b*n.e+t.d*n.f+t.f}}export function affineInvert(t){const n=t.a*t.d-t.b*t.c,e=t.d/n,o=-t.b/n,s=-t.c/n,c=t.a/n;return{a:e,b:o,c:s,d:c,e:-(e*t.e+s*t.f),f:-(o*t.e+c*t.f)}}export function affinePoint(t,n,e){return{x:t.a*n+t.c*e+t.e,y:t.b*n+t.d*e+t.f}}export function affineVector(t,n,e){return{x:t.a*n+t.c*e,y:t.b*n+t.d*e}}export function affineSwapsAxes(t){return Math.abs(t.a)<1e-9&&Math.abs(t.d)<1e-9&&Math.abs(t.b)>1e-9}function y(t,n){return Math.sqrt(t*t-(n/2)**2)}export function isInsideWafer(t,n,e){const o=t-e.center.x,s=n-e.center.y;if(o*o+s*s>e.radius*e.radius)return!1;if(e.notch){const c=y(e.radius,e.notch.length);if(e.notch.type==="bottom"&&s<-c||e.notch.type==="top"&&s>c||e.notch.type==="left"&&o<-c||e.notch.type==="right"&&o>c)return!1}return!0}export function clipDiesToWafer(t,n,e){const o=[];for(const s of t){const c=isInsideWafer(s.physX,s.physY,n);if(!e){c&&o.push({...s,insideWafer:!0,partial:!1});continue}const a=e.width/2,i=e.height/2,r=[[s.physX-a,s.physY-i],[s.physX+a,s.physY-i],[s.physX+a,s.physY+i],[s.physX-a,s.physY+i]].filter(([h,p])=>isInsideWafer(h,p,n)).length;!c&&r===0||o.push({...s,insideWafer:!0,partial:r<4})}return o}export function applyOrientation(t,n){if(n.orientation===0)return t;const e=affineRotation(n.orientation,n.center.x,n.center.y);return t.map(o=>{const s=affinePoint(e,o.physX,o.physY);return{...o,physX:s.x,physY:s.y}})}export function transformDies(t,n,e={x:0,y:0}){const{rotation:o=0,flipX:s=!1,flipY:c=!1}=n;if(o===0&&!s&&!c)return t;const a=affineCompose(affineMirror(s,c,e.x,e.y),affineRotation(o,e.x,e.y));return t.map(i=>{const f=affinePoint(a,i.physX,i.physY);return{...i,physX:f.x,physY:f.y}})}export function mapDataToDies(t,n,e){const{valueField:o,matchBy:s="xy"}=e,c=new Map,a=r=>{const h=c.get(u(r));if(h===void 0)return{...r};const p=r.testValues??{};return{...r,testValues:{...p,[Object.keys(p).length]:h}}};if(s==="ij"){const r=e.iField??"x",h=e.jField??"y";for(const p of n)c.set(`${+p[r]},${+p[h]}`,+p[o]);return t.map(a)}const i=e.xField??"x",f=e.yField??"y";for(const r of n)c.set(`${+r[i]},${+r[f]}`,+r[o]);return t.map(a)}
1
+ import{getDieKey as l}from"./dies.js";export function rotatePoint(t,n,e,o=0,s=0){const c=e*Math.PI/180,i=Math.cos(c),f=Math.sin(c),a=t-o,r=n-s;return{x:o+a*i+r*f,y:s-a*f+r*i}}export function affineIdentity(){return{a:1,b:0,c:0,d:1,e:0,f:0}}export function affineRotation(t,n=0,e=0){const o=t*Math.PI/180,s=Math.cos(o),c=Math.sin(o);return{a:s,c,b:-c,d:s,e:n-(s*n+c*e),f:e-(-c*n+s*e)}}export function affineMirror(t,n,e=0,o=0){return{a:t?-1:1,c:0,b:0,d:n?-1:1,e:t?2*e:0,f:n?2*o:0}}export function affineCompose(t,n){return{a:t.a*n.a+t.c*n.b,b:t.b*n.a+t.d*n.b,c:t.a*n.c+t.c*n.d,d:t.b*n.c+t.d*n.d,e:t.a*n.e+t.c*n.f+t.e,f:t.b*n.e+t.d*n.f+t.f}}export function affineInvert(t){const n=t.a*t.d-t.b*t.c,e=t.d/n,o=-t.b/n,s=-t.c/n,c=t.a/n;return{a:e,b:o,c:s,d:c,e:-(e*t.e+s*t.f),f:-(o*t.e+c*t.f)}}export function affinePoint(t,n,e){return{x:t.a*n+t.c*e+t.e,y:t.b*n+t.d*e+t.f}}export function affineVector(t,n,e){return{x:t.a*n+t.c*e,y:t.b*n+t.d*e}}export function affineSwapsAxes(t){return Math.abs(t.a)<1e-9&&Math.abs(t.d)<1e-9&&Math.abs(t.b)>1e-9}function d(t,n){return Math.sqrt(t*t-(n/2)**2)}export function isInsideWafer(t,n,e){const o=t-e.center.x,s=n-e.center.y;if(o*o+s*s>e.radius*e.radius)return!1;if(e.notch){const c=d(e.radius,e.notch.length);if(e.notch.type==="bottom"&&s<-c||e.notch.type==="top"&&s>c||e.notch.type==="left"&&o<-c||e.notch.type==="right"&&o>c)return!1}return!0}export function clipDiesToWafer(t,n,e){const o=[];for(const s of t){const c=s.physX,i=s.physY,f=isInsideWafer(c,i,n);if(!e){f&&o.push({...s,insideWafer:!0,partial:!1});continue}const a=e.width/2,r=e.height/2,p=[[c-a,i-r],[c+a,i-r],[c+a,i+r],[c-a,i+r]].filter(([h,y])=>isInsideWafer(h,y,n)).length;!f&&p===0||o.push({...s,insideWafer:!0,partial:p<4})}return o}export function applyOrientation(t,n){if(n.orientation===0)return t;const e=affineRotation(n.orientation,n.center.x,n.center.y);return t.map(o=>{const s=affinePoint(e,o.physX,o.physY);return{...o,physX:s.x,physY:s.y}})}export function transformDies(t,n,e={x:0,y:0}){const{rotation:o=0,flipX:s=!1,flipY:c=!1}=n;if(o===0&&!s&&!c)return t;const i=affineCompose(affineMirror(s,c,e.x,e.y),affineRotation(o,e.x,e.y));return t.map(f=>{const a=affinePoint(i,f.physX,f.physY);return{...f,physX:a.x,physY:a.y}})}export function mapDataToDies(t,n,e){const{valueField:o,matchBy:s="xy"}=e,c=new Map,i=r=>{const u=c.get(l(r));if(u===void 0)return{...r};const p=r.testValues??{};return{...r,testValues:{...p,[Object.keys(p).length]:u}}};if(s==="ij"){const r=e.iField??"x",u=e.jField??"y";for(const p of n)c.set(`${+p[r]},${+p[u]}`,+p[o]);return t.map(i)}const f=e.xField??"x",a=e.yField??"y";for(const r of n)c.set(`${+r[f]},${+r[a]}`,+r[o]);return t.map(i)}
@@ -1,5 +1,5 @@
1
1
  import type { Wafer } from '../core/wafer.js';
2
- import type { Die } from '../core/dies.js';
2
+ import type { Die, PositionedDie } from '../core/dies.js';
3
3
  import type { Reticle } from '../core/reticle.js';
4
4
  import type { DieMetadata, WaferMetadata } from '../core/metadata.js';
5
5
  import { type Affine } from '../core/transforms.js';
@@ -382,7 +382,7 @@ export interface MapTitleParts {
382
382
  * the bin on single-bin stacked cards.
383
383
  */
384
384
  export declare function buildMapTitle(view: View, fallbackFormat?: 'si' | 'engineering', binDefs?: BinDef[]): MapTitleParts;
385
- export declare function generateTextOverlay(dies: Die[], txCoords: Float64Array | null, options: {
385
+ export declare function generateTextOverlay(dies: PositionedDie[], txCoords: Float64Array | null, options: {
386
386
  plotMode: PlotMode;
387
387
  colorFns: ColorFns;
388
388
  normalize: (v: number) => number;
@@ -403,7 +403,7 @@ export declare function generateTextOverlay(dies: Die[], txCoords: Float64Array
403
403
  * buildView(wafer, dies, { plotMode: 'hardBin', reticles })
404
404
  * ```
405
405
  */
406
- export declare function buildView(wafer: Wafer, dies: Die[], options?: ViewOptions, binDefs?: {
406
+ export declare function buildView(wafer: Wafer, dies: PositionedDie[], options?: ViewOptions, binDefs?: {
407
407
  hbinDefs?: BinDef[];
408
408
  sbinDefs?: BinDef[];
409
409
  metadataFields?: MetadataFieldDef[];