The physics and mathematics of the quantum atom — from the Bohr model to wavefunction probability clouds and atomic emission spectra.
Niels Bohr proposed that electrons orbit the nucleus in discrete circular shells, each with a fixed energy. Electrons can jump between shells by absorbing or emitting photons of exactly the right energy.
The Bohr model correctly predicts hydrogen spectral lines but fails for multi-electron atoms. It was superseded by quantum mechanics, which describes electrons as probability waves rather than point particles on fixed orbits.
The full quantum description of the electron comes from Schrödinger's equation. Its solutions — wavefunctions ψ — are characterised by three quantum numbers (n, l, mₗ) and describe the probability amplitude of finding the electron at any position.
The cloud visualization in this simulator places dots randomly with probability proportional to $|\psi|^2$. The shape you see is where the electron is most likely to be found — not a fixed orbit. The electron has no definite position until measured.
Each electron state is fully described by four quantum numbers. The first three come from the Schrödinger equation; the fourth (spin) comes from Dirac's relativistic quantum theory.
Shell capacities follow from this: K (n=1) holds $2(1)^2=2$ electrons, L holds $2(2)^2=8$, M holds $2(3)^2=18$, N holds $2(4)^2=32$.
The angular part of the wavefunction is described by real spherical harmonics $Y_l^m(\theta,\phi)$. These give each orbital type its characteristic 3D shape.
In the Orbital Shapes mode, this engine uses the squared spherical harmonics as a radial weighting to place cloud dots — larger $|Y_l^m|^2$ at a given angle means more dots there. The result is a 3D point-cloud isosurface of each orbital's probability lobe.
When an electron drops from a higher shell to a lower one it emits a photon whose energy exactly equals the energy difference. Different transitions emit different colours — this is the atom's unique spectral fingerprint.
Named series: Lyman (n→1, UV), Balmer (n→2, visible), Paschen (n→3, infrared). The visible Balmer lines — red (Hα 656nm), cyan (Hβ 486nm), violet (Hγ 434nm) — are the classic hydrogen spectrum.
Click any electron in the simulation to excite it. The emitted wavelength appears as a bright line in the spectrum bar. The color maps wavelength 380–700nm → visible RGB using a piecewise linear approximation of the human eye's response.
Electrons fill orbitals in a specific order — lowest energy first. The Aufbau principle, Hund's rule, and the Pauli exclusion principle together determine the ground-state electron configuration of every element.
This engine covers H (Z=1) to Kr (Z=36) with correct configurations including the Cr and Cu anomalies. Use the arrows or keyboard ← → to browse elements. ↑ ↓ jumps by 10.
| Input | Action |
|---|---|
| Mouse drag (canvas) | Rotate atom in 3D |
| Scroll wheel | Zoom in / out |
| Click electron | Excite → emission line appears |
| ← → arrows / panel buttons | Previous / next element |
| ↑ ↓ arrows | Jump 10 elements forward / back |
| Mode buttons | Switch: Bohr / Quantum Cloud / Orbital Shapes |
| Shell buttons | Toggle individual shell visibility |
| Nucleus zoom slider | Zoom into nucleus to see protons / neutrons |
Implementation notes and pseudocode for the 3D quantum atom rendering engine.
// Applied to every point: electrons, nucleus particles, cloud dots function project(x, y, z): // 1. Rotate around Y axis (user drag — left/right) x1 = x*cos(rotY) + z*sin(rotY) z1 =-x*sin(rotY) + z*cos(rotY) // 2. Rotate around X axis (user drag — up/down) y2 = y*cos(rotX) - z1*sin(rotX) z2 = y*sin(rotX) + z1*cos(rotX) // 3. Perspective divide depth = z2 + 700 // push behind camera if depth < 5: return null s = 500 / depth // focal length = 500 sx = centreX + x1 * s * zoom sy = centreY + y2 * s * zoom return { sx, sy, s, depth }
// Precomputed once per orbital type (n, l) // Uses hydrogen-like radial + angular wavefunctions function buildCloud(n, l, shellRadius): pts = [] while pts.length < N_CLOUD_POINTS: r = random(0, shellRadius * 2.2) // radial distance theta = acos(2*random() - 1) // polar angle phi = random(0, 2π) // azimuthal angle // Radial probability (simplified hydrogen-like) rn = r / shellRadius P_radial = r² * exp(-2*rn/n) * (polynomial in rn) // Angular probability (real spherical harmonics) if l==0: P_ang = 1 // s: sphere elif l==1: P_ang = |cos(theta)|² + ... // p: dumbbell elif l==2: P_ang = sin²θ*cos²θ*(1+cos2φ) // d: cloverleaf elif l==3: P_ang = |cos(3φ)|*sin³θ*cos²θ // f: complex if random() < P_radial * P_ang * K: pts.push(sphericalToCartesian(r, theta, phi)) return pts
function exciteElectron(eIdx): e = electrons[eIdx] n1 = orbitals[e.orbIdx].n // ground shell n2 = random(n1+1, min(n1+2, 4)) // excited shell // Energy of emitted photon dE = 13.6 * (1/n1² - 1/n2²) // eV lam = 1240 / dE // wavelength in nm // Animate excitation e.exciteLevel = 1 e.exciteTimer = 1.5 // seconds until drop back // Add line to emission spectrum if 380 < lam < 750: specLines.push({ lam, life: 1 }) drawSpectrumLine(lam)
| System | Complexity | Count per frame |
|---|---|---|
| Cloud point projection | O(C) | ~4000 pts per active orbital |
| Depth sort (cloud) | O(C log C) | Sort then draw back→front |
| Nucleus projection | O(P) | P = protons + neutrons |
| Electron update | O(E) | E ≤ 36 electrons (Kr) |
| 3D rotation | O(N) | 6 multiplies per point |
| Cloud precompute | Once per orbital | ~8 clouds × 4000 pts cached |