PSFCraft WebUI¶
Interactive, browser-based PSF (Point Spread Function) visualisation tool.
Distributed as a single static HTML file — no build step, no package manager,
no external CDN dependencies. Works on any modern browser, including file:// origins.
Live Demo¶
Try the WebUI directly in your browser — no installation required:
Fullscreen
Use the dedicated controls inside the WebUI to maximise the canvas. If the iframe is too small, you can also open the standalone app ↗ in a new tab.
Quick start¶
# Open directly in the browser — no server required
xdg-open psfcraft-webui.html # Linux
open psfcraft-webui.html # macOS
start psfcraft-webui.html # Windows
Or serve locally (avoids file:// cross-origin quirks in strict browser configs):
python -m http.server 8080 # then visit http://localhost:8080/psfcraft-webui.html
Features¶
| Feature | Description |
|---|---|
| Real-time PSF | Diffraction PSF recomputed on every slider change via in-browser FFT |
| Zernike controls | Defocus, Astigmatism 0°/45°, Coma X/Y, Trefoil, Spherical (OSA/ANSI indexing) |
| Aperture types | Newtonian (3-spider), Newtonian (4-spider), Circular (clear), Annular |
| View modes | PSF intensity / Aperture mask / Wavefront Error (WFE) map |
| Split mode | Two independent optical systems rendered side by side on one canvas |
| Decomp mode | One PSF tile per Zernike term (isolated contribution); shared colour scale |
| Colormaps | Inferno, Viridis, Hot, Gray, Coolwarm |
| Intensity scale | Log (default) or linear; adjustable min/max display range |
| Pixel binning | Simulates detector undersampling (1 × – 64 ×) |
| Detector noise | Poisson shot + Gaussian read noise with flux and read-noise sliders |
Architecture¶
The file is self-contained (< 1 300 lines). The JavaScript is structured into
twelve named sections separated by banner comments:
| § | Name | Exports |
|---|---|---|
| 1 | 2-D FFT | fft1d, fft2d, fftShift |
| 2 | Pupil mask | buildPupil |
| 3 | Zernike polynomials | zernikeValue, buildWFE |
| 4 | PSF computation | computePSF, binPSF, applyNoise |
| 5 | Colormaps & colour utilities | CMAPS, lerp, applyColormap, wfeColor, renderDivergingColorbar |
| 6 | Canvas renderers | renderAperture, fillWFEPixels, renderWFE, renderPSF |
| 7 | PSF metrics | measureFWHM, rmsWFE |
| 8 | Application state | state |
| 9 | PSF cache | psfCache, psfCacheKey, getCachedPSF |
| 10 | Render scheduler & doRender |
scheduleRender, doRender, renderSingleMode, renderSplitMode |
| 11 | Decomposition mode | DECOMP_TERMS, renderDecomp |
| 12 | UI wiring & boot | setMode, setView, wireSlider, DOMContentLoaded |
How PSF computation works¶
buildPupil(N, aperture, obscuration)
→ Float32Array[N×N] amplitude mask P(x,y) ∈ {0, 1}
buildWFE(N, coefficients)
→ Float64Array[N×N] wavefront error W(x,y) [λ units]
Complex pupil U = P · exp(2πi · W)
fftShift → fft2d → fftShift (Fraunhofer diffraction)
PSF = |U|², normalised so Σ PSF = 1
binPSF(PSF, N, b) (optional detector binning)
applyNoise(PSF, flux, readNoise) (optional Poisson + Gaussian noise)
The PSF is computed at full resolution N and cached. Binning and noise are
applied after retrieval from the cache, so changing the sampling factor or noise
level never invalidates the expensive FFT step.
Performance notes¶
| Grid size | Typical render time |
|---|---|
| 128 × 128 | < 10 ms |
| 256 × 256 | 20–60 ms |
| 512 × 512 | 150–500 ms |
Times measured on a mid-range desktop CPU in Chrome 124.
The PSF cache (getCachedPSF) memoises up to 40 unique
(aperture, obscuration, coefficients, N) combinations; subsequent renders for
the same configuration are free.
Development notes¶
- No build step. Edit
psfcraft-webui.htmldirectly. - Indentation: 2 spaces (matching the rest of the project's JS conventions).
- Style: ES2020+,
"use strict",const/letonly, JSDoc on public functions. - Testing: Open the file in a browser and exercise all controls. Automated headless tests are not yet implemented.
Adding a new Zernike term¶
- Add a
zernikeValuecasein § 3. - Add a slider row in the HTML
<aside id="sidebar">and in<aside id="panel-ctrl-R">. - Register it in the
aberDefsLandaberDefsRarrays in § 12. - Add the term to
DECOMP_TERMSin § 11 if it should appear in Decomp mode.
Deployment (GitLab Pages)¶
The file is automatically copied to public/webui/index.html during the
documentation build. After a successful push to main the WebUI is accessible at:
https://<namespace>.pages.gitlab.io/<project>/webui/
The copy step is handled in Makefile (pre-build target):
mkdir -p public/webui
cp webui/psfcraft-webui.html public/webui/index.html