diff ref struct Rietveld refinement for the Mac · powder diffraction with X-rays, synchrotron and neutrons · started October 2026

The analysis in the browser: a public web app on the core compiled to WebAssembly, the user’s own files, the series recognised and its maps offered

The analysis in the browser: a public web app on the core compiled to WebAssembly, the user's own files, the series recognised and its maps offered migrated

I10 · an idea of the seed-place, on its way to the extension.

Said
2026-10-25, Josu
Status
migrated
Home
extension (where it migrates)
Needs
I08
Requirement
R34
Version
diff-ref-struct Web 24d8619 on core 0.81.0 (jmigartua.github.io/diff-ref-struct-web)

The idea

Said on 25 October 2026, after the ESRF series was worked with the interactive map (L421; esrf-datuak-irene L021): a standalone, full HTML app, public on Josu's repositories, so that anyone with the URL has a UI for this kind of analysis: access to the user's local file structure to load the files, and then the app offers the possible map plots from the files. And for the present page: the project's navigation on the left as in the apps, an inspector, with a < to shrink it and a draggable separator; a toggle for the y axis between the interval adapted to the file shown and one fixed to the whole set's maximum, to see how things change; a toggle between the √ values and the raw values of the files, since the differences between peaks are often not so large that √ is needed; the map's vertical axis shows hours, should it be temperatures; a richer file inspector in every sense: icons, selecting files one by one or all at once. "Innovate, propose, be wise: a powerful tool that should be in the instruments at the ESRF so that the users do not have to do all this."

Assessment

What exists. The Map viewer is one module hosted by the app and by the page the core writes (I08, step 18, L412); the page is the app's map in a browser but holds one set's numbers and no core. The Plots module talks to the core through one function (invoke in app/ui/core.js, sixty calls go through it) and its own code computes nothing (PL14). The core has no mandatory dependency (serde optional) and its readers work from text (data::read(text, ins)), the file paths being wrapped around them; plots::open takes paths, one std::fs call. The project site's public repository is built by an Action from the private one.

The one architecture that keeps L139. The core compiled to WebAssembly and run in the browser: the same crate, the same functions, no second implementation. The browser host is the app's shell without Tauri: the module and the viewer as they are, invoke replaced by a dispatcher onto the wasm core (one function). What the core needs for it: an entry that opens a set from names and bytes instead of paths (plots::open_from(&[(name, text, variable)]), the readers already being text functions), and a wasm build with the plots subset as a feature (the whole core would be a few MB; the subset less). Set aside: a server that runs the core and receives the files (unpublished measurements uploaded to a machine of ours, a server to keep, and nothing works in a hutch without the network); the map's arithmetic written in JavaScript (two implementations, against L139).

The user's files. Nothing leaves the machine: the app is a static site, the files are read in the browser. Chrome and Edge give a folder through the File System Access API (showDirectoryPicker): the inspector shows the tree, handles are kept, and a folder can be read again, which gives the instrument's case for free, a live mode in which the map grows as the scans land in the folder. Safari and Firefox give a folder once (<input webkitdirectory>) and files by drag and drop; everything but live mode works there. Installable as a PWA and usable offline after the first visit (a beamline hutch).

"The possible map plots from the files." This is a function of the core, not of the UI: a series detector that reads each file's facts (the registry's: format, points, step, λ, title, temperature where the header or the name gives it, the elapsed time, the exposure class) and finds the structure of the run — a ramp with one scan per temperature, holds as runs of equal temperature against time, the whole run against time, several exposure classes — and proposes sets: for the ESRF run, "25 scans, one per temperature, 900–1300 °C", "100 scans against time", "the 1270 °C hold, 39 scans against time". It is what F07 and the timeline S01–S12 of esrf-datuak-irene were found by hand; plots::propose(files), each proposal a set the user accepts into the Map.

Josu's points on the present page, each in its place:

  • The inspector on the left with < and a draggable separator: the web host's layout (the app has the sidebar already; the page of I08 was the viewer alone).
  • The y interval shared by the whole set or adapted to the file shown: a toggle of the shared plot for the row strip and the curves (Overlay, Stack), the shared range being the set's extent the core gives.
  • √ against the raw values: the map's scale is already a choice in the app (linear, √, log; PL27) and the ESRF sets were saved on √; the page lacks the control because it has no core to recompute: in the web host the toggle is live; the static page keeps one scale (or embeds a second on request, at twice the size).
  • Hours or temperatures on the vertical axis: the hundred-scan set is against time because many scans share a temperature (the holds) and a map needs one row per value; the temperature belongs on a second axis at the right, each row labelled with its temperature, as esrf-datuak-irene's I01 asked from the start. That needs a member to carry a second variable in the set (t the axis, T the label): a core request, and the by-temperature-map set remains the one with temperature as the axis.
  • A richer inspector: icons by the file's kind (the core's describe names the kind), checkboxes per file and all/none/by class/by temperature range, sort by temperature, time or name, the file's facts on hover, dim and solo (the app's members table has these two).

For the instrument, beyond the asks. Live mode (above); the series detector; the Series view's window integrals against temperature or time with the cursors (exist) and, later, a transition finder on them (a kink in a window's integral, the core's); export of any view as SVG and PNG from the browser; the set as a .drv downloaded and dropped back (the state travels as a file; the data never do); the view in the URL's hash. Not in the browser: Publish's figures (LaTeX) and, for now, refinement, both the desktop's.

Costs and risks. The wasm toolchain is not installed (wasm-pack); the bytes entry is a small refactor of the readers' wrappers; the wasm's size and start time on a hutch machine; live mode is Chromium-only; a hundred scans at 27 000 points is 2.7 M points in memory, fine. The public repository holds the built app (the wasm, the JS, the page), not the core's source.

Proposal

  • Step 0, now, in the app and the page (Plots and the core): the y toggle shared/own in the shared plot; a second variable per member in the set file and the map's right-hand axis labelled with it (core, then Plots); the richer members table (icons, all/none/by class, sort). Josu's three asks that do not wait for the web host.
  • Step 1, the core in the browser: plots::open_from (names and text), a wasm feature with the plots subset, the crate built with wasm-pack and called from node in a test on the \(\mathrm{Tb_{2}Pd_{2}Sn}\) files: the same map as drs plots map, to the bit.
  • Step 2, the web host: web/ (the stream's design) and app/ui/host-web/: the app's shell files and the Plots module as they are, invoke dispatched to the wasm core; the inspector on the left with < and the separator, the folder picked or dropped; the Map, the clip, the cursors, the zoom, the regions working on files that never leave the browser. Hosted locally first.
  • Step 3, the series detector: plots::propose(files) in the core, tested on the ESRF run's 101 names and facts (the three sets found); the host offers the proposals and opens the chosen one.
  • Step 4, live mode and offline: the folder read again on a timer (Chromium), the map growing; a service worker, the app installable; the .drv down and up; the view in the hash.
  • Step 5, public: the repository diff-ref-struct-web (Pages), built and pushed by an Action from the private repository as the site is; the URL on the project site; a page for the instrument's users that says what the app does and that nothing is uploaded.
  • Later: export of figures from the browser, the transition finder, the Series view's full set, refinement in wasm.

For Josu to decide

  • The name and the address: proposed diff-ref-struct Web at jmigartua.github.io/diff-ref-struct-web, the public repository holding the built app only.
  • Step 0 first? Its three parts can go to Plots and the core now, before the web stream exists.
  • Chromium first for live mode (the instrument's case), everything else in every browser: agreed?
  • Both hosts kept: the static page of drs plots show for a map sent by mail, the web app for the work?
  • A stream of its own (web/, branch web, OpenCode for the UI, Claude Code for the core's wasm part), or the Plots stream widened?

The idea's log

  • 2026-10-25 · said

    Said by Josu after the ESRF series was worked with the interactive map: a standalone public web app, the user's local files, the possible maps offered from them; the inspector on the left with a shrink and a separator; a shared/own y interval toggle; √ or raw values; hours or temperatures on the map's axis; a richer file inspector. Assessed the same day: the core compiled to WebAssembly in the browser host of the same module, the files read in the browser and never uploaded, a series detector in the core, live mode for the instrument; five steps and a step 0 for the asks that need no web host. L422

  • 2026-10-25 · decision

    Green, the same day: Josu says yes to every proposal of the assessment (the name diff-ref-struct Web at jmigartua.github.io/diff-ref-struct-web with the public repository holding the built app; step 0 first; Chromium first for live mode; both hosts kept; a stream of its own) and asks for it by the next morning, the files waiting to be analysed. R34 appended; the web stream opened (web/, branch web, worktree ../20261009_diff-ref-str-web); W1–W3 filed to the core, W4 to Plots; three orders at once: the core (W1, W3, then W2), Plots (W4), the web host (step 2 on the dispatcher's stub until W1 lands). L423

  • 2026-10-25 · migration

    Migrated, the same day: diff-ref-struct Web is public at jmigartua.github.io/diff-ref-struct-web, built and pushed by the Action from main (web 24d8619, core 0.81.0). The five steps built in two rounds of three parallel orders (L424–L428): the core in WebAssembly, the browser host with the inspector, the files read in the browser and never uploaded, the series detector finding the ESRF run's three sets as they were built by hand, live mode, offline, the address in the hash, the public repository. Checked on the public page with the 101 ESRF files (L429). L429