Skip to content

Add a web page solving instances with the WebAssembly module - #634

Merged
fontanf merged 1 commit into
masterfrom
wasm-web-page
Oct 3, 2026
Merged

fontanf merged 1 commit into
masterfrom
wasm-web-page

Conversation

@fontanf

@fontanf fontanf commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Stacked on #633, itself on #632. This PR's diff only shows the third step. GitHub retargets it as the base PRs are merged.

The page (wasm/web/)

A static page; the computation runs in the browser, in the Web Worker of #633.

  • Input:
    • a form for the bin and item types and the objective, for every problem type but irregular, with "Load an example" (the README examples);
    • or a JSON instance, typed or loaded from a file. That's the only input for irregular, whose shapes don't fit in a table.
  • Parameters: the optimization mode (anytime by default) and the time limit. "Stop" ends the optimization with its best solution.
  • Results: a progress table, with each update's solution and bound, and the plot of the best solution, redrawn as solutions are found (at most twice a second). The certificate and the output can be downloaded.
  • If the page isn't served with the headers enabling SharedArrayBuffer, it explains it instead of failing.

python3 wasm/web/serve.py serves it with those headers. wasm/README.md explains how to build, test and serve it.

Visualizers (wasm/web/visualize/)

JavaScript ports of the six plotly visualizers of python/packingsolver/visualize/, with the same options. Each returns {data, layout} for Plotly.newPlot. plotly.js is loaded from jsDelivr, at version 4.1.1, the one plotly.py 7.1 uses.

  • Tested against Python: wasm/tests/visualize.test.mjs checks the JavaScript figures against the Python ones, stored as fixtures in wasm/tests/fixtures/visualize/ (1.1 MB). That's 68 cases: the certificates of the Python visualizer tests, every option, and a few hand-made certificates for features the repository's certificates don't cover (defects, weights, arcs).
    • generate_visualize_fixtures.py regenerates the fixtures; it needs plotly.
    • Numbers are compared with a 1e-9 relative tolerance, because of the trigonometric functions of the irregular arcs.
  • Shared subplot layout: common.js reproduces plotly.subplots.make_subplots. It's identical to plotly.py on every grid from 1x1 to 5x5, 2D and 3D, to the last bit.

Worker fix

Loaded with importScripts in a Web Worker, the Emscripten module took the worker's URL as its own script's, and starts its threads from that URL. The worker now passes mainScriptUrlOrBlob.

Testing

  • Node: node --test wasm/tests/ gives 99 tests, all passing: the 31 of WebAssembly module: all problem types, sessions and a Web Worker #633 and the 68 visualizer cases.
  • Headless Chromium 154, driving the page through the DevTools protocol, with the page unchanged:
    • crossOriginIsolated is true;
    • each problem type solves its example (or a JSON instance for irregular) in anytime mode with a 5 s time limit, and the plot is drawn, 2D and 3D;
    • "Stop" with no time limit ends the optimization within 0.25 s;
    • no console errors.
  • Not tested in Firefox or Safari.

Notes on the Python visualizers

The ports reproduce them as they are, but these looked off while porting:

  • Legend groups: the "ID" coloring uses item, the others items.
  • With the "ID" coloring, each bin gets an empty trace for each missing item id. In the first bin they appear in the legend, while item types only in later bins get no legend entry.
  • rectangle:
    • the centre of gravity is divided by the bin's WEIGHT column, but its percentages are divided by the sum of the item weights;
    • the gravity marker is a skewed band rather than a line;
    • with the "DENSITY" coloring, a color group keeps the density of its last item only.
  • box ignores the bin COPIES column: a bin used several times is drawn once. boxstacks only uses it with expand_copies.
  • With no bin, or with columns=0, the grid computation divides by zero.

@fontanf
fontanf force-pushed the wasm-all-types-worker branch from 31eed86 to 81983ec Compare October 3, 2026 19:17
Base automatically changed from wasm-all-types-worker to master October 3, 2026 19:18
'wasm/web/' is a static page: the instance is entered in a form (every
problem type but irregular) or as a JSON file, solved in the Web Worker
with the chosen optimization mode and time limit (and a 'Stop' button),
and its solutions are drawn as they are found. The certificate and the
output can be downloaded.

- 'wasm/web/visualize/': JavaScript ports of the plotly visualizers of
  'python/packingsolver/visualize/'. 'wasm/tests/visualize.test.mjs'
  checks that they give the same figures as the Python ones, stored in
  'wasm/tests/fixtures/visualize/' ('generate_visualize_fixtures.py').
- 'wasm/web/serve.py': development server, with the headers enabling
  'SharedArrayBuffer'.
- The Web Worker gives the module the URL of its own script, which its
  threads are started from: loaded with 'importScripts', it took the URL of
  the worker.
- 'wasm/README.md' explains how to build, test and serve it.
@fontanf
fontanf merged commit bfe1fa0 into master Oct 3, 2026
0 of 3 checks passed
@fontanf
fontanf deleted the wasm-web-page branch October 3, 2026 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant