buildWaferMap is CPU-intensive on large datasets and would block the main thread.
createWafermapWorker wraps a native Worker and runs buildWaferMap off-thread — the page stays responsive while building.
The loading spinner is shown until worker.run(input) resolves; the timing badge shows how long the worker took.
Rendering (renderWaferMap) always runs on the main thread after the promise resolves.
Note: the worker trades total speed for responsiveness — copying data across postMessage makes it slower overall than building directly, so it only pays off when a build is large enough to visibly freeze the page. For small datasets, build on the main thread.