© 2026 Hohlbein et al. · CC BY 4.0 · GitHub · All client-side, no upload.
Both windows have content — pick which to export as PNG.
field op value, joined with and/or
(e.g. intensity > 1000 and uncertainty < 20); Enter commits a clause, clauses stack
cumulatively. Type reset to clear all of them. Start typing a field name for
autocomplete suggestions (↑/↓ to move, Enter/Tab to accept) — covers both the current table's
columns and the tempClusteringXY/tempClusteringZ fields below.sigma_xy is the fitted PSF width (average of σx/σy for
astigmatic 3D). sigma_z, shown for MLE 3D results, is an approximate z-precision:
the fit's own uncertainty on σx/σy propagated through the calibration curve's local slope at the
found z — not a full joint fit (z isn't a parameter of the pixel-level fit, σx/σy are), but the
best estimate available from what the fit reports. Not available for Phasor 3D.tempClusteringXY < 10 (nm) merges the same molecule's
detections across consecutive frames into one higher-precision "event" (photon-weighted position,
summed intensity, properly combined uncertainty); tempClusteringZ < value adds the same
in z. One threshold per axis (a new value replaces the old). Once active, counts switch from
localizations to events and the table gains an nmerged column. A gap frame always breaks
the chain for now (planned: tempClusteringMemory). FRC resolution can get coarser after
clustering, not finer — counter-intuitive, but FRC measures achieved image resolution, which depends
on point density as well as per-point precision; merging improves the latter but sharply reduces
the former (far fewer points), and if that density loss outweighs the precision gain, FRC's number gets
worse even though individual events really are more precise. Check the uncertainty column's
histogram (not FRC) to see the precision improvement in isolation.A proof-of-concept single-molecule localization pipeline that runs entirely in your browser. Nothing is uploaded.
.tif/.tiff stack, or Simulate movie for a test dataset (open Simulation settings to adjust frames, blink density and photons).TIFF headers are parsed first to get the frame count and dimensions, then the decoded working-set size is estimated (frames × width × height × 4 bytes).
If it fits the memory budget (default 3 GB, adjustable) all frames are decoded into RAM with a progress bar — changing the threshold and re-running is then instant (no re-decode).
If it exceeds the budget, the loader streams: frames are decoded as the analysis reaches them and discarded again, so memory stays bounded no matter how long the stack is. Trade-off: re-running re-decodes. For ordinary TIFFs this happens in heaps of ~500 MB (adjustable) because every frame must pass through the TIFF decoder; one heap is decoded, localized, freed, then the next. This is exactly the pattern that would let you localize a live camera buffer in real time.
Large ImageJ stacks (above ~4 GB) are written with a single directory entry and all frames laid out contiguously after it, because 32-bit TIFF offsets cannot address further. webSMLM detects this from the images=N record and indexes frames arithmetically, decoding one at a time — no heaps needed.
The file itself is never read into memory whole — frames are pulled on demand via File.slice(), so a multi-GB stack stays bounded by the memory/chunk budget above regardless of on-disk size.
Bit depth (8/16/32-bit) and endianness are handled automatically; 16-bit is preserved (not flattened to 8-bit).
Band-pass filter (Difference of Gaussians). Each frame is blurred at a small scale (0.8×PSF σ) and a large scale (3×PSF σ); the large-scale blur is subtracted from the small-scale one. This removes flat background and slow gradients while keeping PSF-sized spots. DoG = G(0.8σ) − G(3σ).
Local-maximum picking with a k·σ threshold. On the filtered image we compute the mean and standard deviation of pixel values, and keep any strict 8-neighbour local maximum whose value exceeds mean + k·σ. Here σ is the noise spread of the band-passed image (not the PSF width), and k is the slider: k = 4 keeps peaks > 4 noise-standard-deviations above background. Lower k → more (dimmer) detections; higher k → fewer, more confident ones. The Wavelet (B-spline) filter (default) replaces the DoG band-pass with an à trous cubic-B-spline wavelet plane, but is thresholded the same k·σ way.
Uniform box filter. Instead of Gaussians, the band-pass is a difference of two box (uniform) averages sized off σ_PSF, and candidates are strict local maxima of that band-pass — over a σ_PSF-sized square window, not just the 8 neighbours — above a plain intensity threshold rather than k·σ. It has no per-frame noise statistic, so the default threshold (25) is in raw camera counts and needs re-tuning per dataset.
Each surviving maximum defines a small ROI (Fit window, e.g. 7×7 px) passed to the fitter.
Phasor (fast). Takes the phase of the first Fourier coefficient of the ROI in x and y to get the sub-pixel centre. No iteration — ~100–170× faster than Gaussian fitting, ~19 nm precision at 900 photons. Great for large stacks and real-time.
Gaussian (least-squares). Fits a 2-D Gaussian to the ROI by Gauss–Newton with a line search (~16 nm at 900 photons). Slightly better precision, much slower.
Gaussian (MLE). Poisson maximum-likelihood fit of an integrated-Gaussian PSF (Smith et al. 2010), by full Fisher-scoring Newton (~5 iterations, cost similar to LS). Statistically optimal at low photon counts, and it reports a proper per-localization CRLB uncertainty (the “uncertainty [nm]” column comes from the Cramér–Rao bound rather than a formula estimate). Candidates whose fit didn't converge within its iteration budget, whose intensity collapsed to the amplitude floor (background mistaken for a spot), or whose CRLB came out non-finite are rejected automatically rather than kept as degenerate localizations.
Note: Gaussian (LS) is ordinary least-squares; Gaussian (MLE) is the Poisson-optimal fit — prefer MLE at low photon counts. Phasor is the speed option.
Localizations are splatted into a high-resolution accumulation image at the chosen Magnification (super-res pixels per camera pixel) and optionally smoothed by Render blur. Both re-render from stored localizations without refitting. The scale bar is computed from your pixel size and the current zoom; scroll/drag/double-click to navigate.
Precision figures above are for the synthetic model; real data depends on your photon count, background and PSF.
What this tool borrows from, and where to read more:
Phasor localization
Spot detection & thresholding
Fitting & precision (why LS ≠ MLE)
picasso/gaussmle.py — see Picasso reference below.Gain/offset estimation (PCFO)
Localization precision (NeNA)
Image resolution (FRC)
Temporal median filtering (FTM)
Drift correction (AIM)
picasso/aim.py (parabolic sub-pixel peak fit replaces the FFT phase refinement; linear interpolation replaces the spline) — see Picasso reference below.Picasso (reference implementation for the ported MLE and AIM drift code above, github.com/jungmannlab/picasso)
Overview
Contributions beyond the author:
webSMLM © 2026 Hohlbein et al., licensed under
CC BY 4.0.
You may share and adapt it, including commercially, with attribution.
Bundled decoders retain their own licenses: UTIF.js and pako are MIT-licensed.