Questing · 2026-07-11 · Quantum Mechanics · Zero Dependencies

SLIT

A particle approaches a wall with two openings. According to quantum mechanics, it does not choose one slit — it passes through both simultaneously. On the far side, the two parts of the wavefunction overlap and interfere, producing a striped pattern that no classical particle could create. This is not a metaphor. This is what the equation predicts, and this is what every experiment confirms.

Open Slit →

What Is Slit?

Slit simulates a quantum particle (an electron, a photon, an atom — the equation is the same for all) encountering a thin barrier with two narrow slits. The particle's state is described by a complex-valued wavefunction ψ(x,y,t), which evolves in real time under the 2D time-dependent Schrödinger equation. What you see on the canvas is the probability density |ψ(x,y,t)|², color-coded by phase — the glowing field that tells you where the particle is likely to be found if you measured it right now.

The simulation begins with a Gaussian wavepacket on the left side of the grid, moving rightward. When it reaches the barrier, some of the wavefunction is reflected; the rest passes through the two slits and diffracts. On the far side, the two diffracted partial waves overlap and interfere — constructive interference creates bright bands (high probability), destructive interference creates dark bands (near-zero probability). The fringe spacing depends on the particle's de Broglie wavelength and the geometry.

The color encodes the complex phase of ψ. Amber means the wavefunction is near phase 0 (real and positive); teal means it is near phase π (real and negative). The coloring oscillates with the wave as it travels, making the wave nature directly visible rather than just the intensity.

The Schrödinger Equation

The time-dependent Schrödinger equation for a free particle (V=0 away from the barrier) is:

iħ ∂ψ/∂t = -ħ²/(2m) ∇²ψ

For a particle in a 2D box with barrier potential V(x,y):
iħ ∂ψ/∂t = [ -ħ²/(2m) ∇² + V(x,y) ] ψ = H ψ

Formal solution: ψ(t+dt) = e^{-iH dt/ħ} ψ(t)

The challenge is computing the matrix exponential e-iH dt for a 128×128 wavefunction. The split-operator (Strang splitting) method makes this tractable: since H = T + V (kinetic + potential), and these two operators do not commute, we approximate:

e^{-iH dt} ≈ e^{-iV dt/2} · e^{-iT dt} · e^{-iV dt/2}   (second-order accurate)

Hard wall (V=∞): just zero ψ at barrier cells after each step.
Free particle (V=0): only the kinetic step survives.

The kinetic propagator is diagonal in k-space:
  e^{-iT dt} ψ(x) = FFT⁻¹[ e^{-i ħk²/(2m) dt} · FFT[ψ](k) ]

Each k-space mode acquires an independent phase rotation — no mode
couples to any other. This is why the step is unconditionally stable.

Why the FFT Makes It Tractable

The kinetic operator T = -ħ²∇²/(2m) is diagonal in momentum space. Its eigenstates are plane waves eikx with eigenvalues ħ²k²/(2m). So to apply e-iT dt: transform ψ to k-space via 2D FFT, multiply each k-mode by e-iħk²dt/(2m), then inverse-FFT back to position space. This requires O(N² log N) operations — exactly 7 butterfly stages for the 128-point FFTs here.

The simulation computes a complete 2D forward FFT, one complex multiplication per k-space cell, and a 2D inverse FFT — five times per animation frame. On a 128×128 grid this is about 14 million floating-point operations per frame, well within what a browser JavaScript engine handles without frame drops.

Per step:
  • fft2d forward: 2 × 128 × (128 × 7 butterflies) ≈ 230K complex mults
  • kinetic multiply: 128² = 16K complex mults
  • fft2d inverse: same as forward
  • absorb + wall: 16K real mults

Per frame (5 steps × 30fps):
  • ≈ 14M float ops/frame
  • ≈ 420M float ops/sec  (well within JS engine capacity)

The Interference Pattern

Once the wavepacket has passed through both slits and the two diffracted partial waves overlap, they add as complex amplitudes — not intensities. At a point P on the screen at distance L from the barrier and transverse displacement y from center:

ψ_total(P) ≈ ψ_slit1(P) + ψ_slit2(P)

Phase difference: Δφ = k · Δr = k · d·sin θ ≈ k · d·y/L

Constructive (bright fringe):  Δφ = 2πn  →  y_n = nλL/d
Destructive (dark fringe):     Δφ = π(2n+1)  →  fringe spacing = λL/d

With λ=10 px, L≈44 px, d=22 px (default):
  fringe spacing = 10 × 44 / 22 = 20 pixels → ~5 visible fringes

The fringe spacing increases when you reduce the slit separation (longer wavelength or closer slits → wider fringes) and decreases when you increase it. This is the standard double-slit result, here computed from the actual wavefunction rather than the far-field approximation.

Why This Isn't Classical

Classical wave optics (Huygens–Fresnel) also produces double-slit interference, and many browser demos use that simpler model. The difference here is that the wavefunction ψ is complex-valued and its squared magnitude gives a probability density — not an intensity. The same equation governs electrons, neutrons, buckyballs, and atoms. Every experiment — from Davisson–Germer (1927) to Jönsson's electron slits (1961) to the 2019 C₆₀ molecule interference experiments — confirms that quantum objects interfere with themselves.

Feynman called the double-slit experiment “the only mystery” of quantum mechanics: if you watch which slit the particle goes through, the fringes disappear. If you don't, they appear. The act of gaining information about the path destroys the interference. This simulation does not model measurement — the wavefunction evolves freely, and both slits are always coherently open.

Boundary Conditions

The FFT implicitly assumes periodic boundary conditions — the grid wraps around. To prevent the outgoing wavepacket from re-entering from the opposite edge, absorbing boundary conditions are applied via a multiplicative window near all four edges:

// Smoothstep absorption ramp (PAD = 16 pixels from each edge)
d = min(x, N-1-x, y, N-1-y)   // distance to nearest edge
if d < PAD:
  ψ[x,y] *= smoothstep(d / PAD)  // = t²(3−2t), t = d/PAD

This kills the wave before it wraps around,
giving clean open-boundary behavior.

When the wave has been substantially absorbed (total norm below ~4% of initial), the simulation resets with a fresh wavepacket. The cycle repeats automatically.

Using the Controls

Slit separation — the center-to-center distance between the two slits in grid pixels (8–48). Wider separation produces finer, more numerous fringes (fringe spacing = λL/d decreases as d increases). Narrow separation produces wide, spread-out fringes.

Wavelength — the de Broglie wavelength λ of the initial wavepacket, in grid pixels (6–18). Shorter wavelength (λ=6) gives tighter fringes; longer wavelength (λ=18) spreads them wider. Changing the wavelength also changes the packet velocity: v = ħk/m = ħ(2π/λ)/m, so a shorter-wavelength packet moves faster across the grid.

Built 2026-07-11 · Pure JavaScript · Canvas 2D · Zero backend · Live demo → · More questing →