A browser-based simulator for light transport in biological tissue using the diffusion approximation. No installation required — open Example.html in any modern browser.
Work in progress. This is an early draft. More features are planned; see the roadmap below.
The simulator currently implements two theoretical models, selectable from the Model dropdown. Each has its own inputs, defaults, and validity checks (see js/physics/); the app is built so additional models can be added without touching shared code.
Farrell, Patterson & Wilson, Med. Phys. 19(4), 1992. A narrow collimated beam entering a homogeneous tissue slab is modelled as an isotropic point source placed one transport mean free path below the surface. The extrapolated boundary condition accounts for the refractive index mismatch at the air–tissue interface. The resulting fluence field is computed analytically per voxel using a real source + image source pair:
Φ(r) = P₀ / (4π D) · [ exp(-μ_eff r₁)/r₁ − exp(-μ_eff r₂)/r₂ ]
Absorption rate density follows directly as A = μ_a · Φ. This model has genuine 3-D spatial structure — the beam enters at a point, and fluence falls off radially from it.
Kubelka, 1948. Unlike FPW1992, this is a 1-D two-flux model: it assumes the sample is illuminated by a perfectly diffuse (Lambertian) flux uniform across the whole top face, and tracks two counter-propagating streams — downward I(z) and upward J(z) — through an arbitrary number of stacked homogeneous layers (e.g. skin, fat, muscle), each with its own absorption K, scattering S, and thickness. Per layer:
a = 1 + K/S
b = sqrt(a² − 1)
γ = b·S·d
Layers are combined bottom-up with Kubelka's adding formula (R = R_layer + T_layer² R_below / (1 − R_layer·R_below)), and the bottom-most layer sits on a non-reflecting (fully absorbing) backing. Fluence is Φ(z) = I(z) + J(z), and absorption follows the same convention as FPW1992: A(z) = K · Φ(z).
Because the physics has no lateral structure, the computed Φ(z)/A(z) depth profile is broadcast identically across every (x, y) voxel column to fit the app's 3-D slice viewer — this is the physically correct picture for KM's own diffuse-illumination assumption, not an approximation of a beam that should vary laterally.
Parameters are model-specific, since FPW1992 and Kubelka-Munk need entirely different inputs — a single beam/slab vs. an arbitrary stack of layers. The parameter panel is generated from the selected model's schema, so it changes shape when you switch models.
FPW1992:
| Symbol | Meaning | Unit |
|---|---|---|
| μ_a | Absorption coefficient | cm⁻¹ |
| μ_s | Scattering coefficient | cm⁻¹ |
| g | Anisotropy factor | — |
| n | Refractive index | — |
| P₀ | Input beam power | W |
| L_x, L_y, L_z | Tissue slab dimensions | cm |
| N_x, N_y, N_z | Voxel count per axis | — |
Derived quantities (μ_s', D, μ_eff, penetration depth δ) are printed in the status bar after each run, along with a warning if the diffusion approximation is weakly justified for the chosen parameters.
Kubelka–Munk (per layer, repeatable — add/remove layers in the panel):
| Symbol | Meaning | Unit |
|---|---|---|
| K | Absorption coefficient | cm⁻¹ |
| S | Scattering coefficient | cm⁻¹ |
| thickness | Layer thickness | cm |
Plus, once for the whole stack:
| Symbol | Meaning | Unit |
|---|---|---|
| P₀ | Incident diffuse power | W |
| L_x, L_y | Lateral extent (sets flux normalisation P₀/(L_x·L_y)) |
cm |
| N_x, N_y, N_z | Voxel count per axis | — |
Derived quantities (total reflectance R, transmittance T, absorbed fraction A, total stack depth L_z) are printed in the status bar, along with a warning per layer if the two-flux approximation is weakly justified.
- Open
Example.htmlin a browser. - Choose a theoretical model from the Model dropdown (pencil beam FPW1992, or the layered Kubelka-Munk stack).
- Set the model's parameters using the sliders (min/max bounds and the value itself are all directly editable). For Kubelka-Munk, use the add/remove-layer controls to build up a stack.
- Click Compute & visualise.
- Use the x / y / z sliders beneath each plot to move the slice planes through the volume.
Two plots are shown side by side: fluence Φ and absorption A, both on a logarithmic colour scale to reveal the full dynamic range.
Example.html — page structure and layout
style.css — dark-theme styling
js/
models.js — model registry: wires each model's compute/validity
functions to its own parameter schema (paramGroups)
ui-params.js — generic parameter-panel builder/reader, driven
entirely by the selected model's schema; handles
both fixed parameter groups and repeatable ones
(e.g. an arbitrary number of tissue layers)
render.js — colormap, colorbar, and 3-slice volume rendering
main.js — simulation state, model switching, run handler,
plot/axis-slider wiring
physics/
fpw1992.js — FPW1992 model: compute() + checkValidity()
kubelkaMunk.js — Kubelka-Munk N-layer model: compute() +
checkValidity()
(add one file per model here; see models.js
for the registration steps)
Each theoretical model is self-contained: its physics, its own parameter definitions (including defaults and ranges), and its own validity checks all live in one file under js/physics/, registered with a short entry in js/models.js. The dropdown, parameter panel, run handler, and warning display all pick up new models automatically.
The following features are planned for future releases:
- Finite laser beams — Gaussian and flat-top beam profiles instead of the infinitely thin pencil beam
- Multi-layered tissue under a point-source beam — the Kubelka-Munk model now covers multi-layered tissue, but only under broad diffuse illumination; a layered point-source model (e.g. multi-layer diffusion) is still open
- Structured light / scanning patterns — multiple beam positions or scanning trajectories
- Monte Carlo validation — optional MC reference run for cross-checking the diffusion result, likely via WebAssembly (Rust + wasm-pack) for the computationally intensive photon transport
- Export — download fluence / absorption volumes as CSV or HDF5 for post-processing in Python / Julia
- Isosurface overlay — 3D isosurface rendering on top of the slice views
T. J. Farrell, M. S. Patterson, B. Wilson, A diffusion theory model of spatially resolved, steady-state diffuse reflectance for the noninvasive determination of tissue optical properties in vivo, Med. Phys. 19(4), 879–888 (1992).
P. Kubelka, New Contributions to the Optics of Intensely Light-Scattering Materials, Part I, J. Opt. Soc. Am. 38(5), 448–457 (1948).