# Blackbody Radiation **The Planck curve emerges from collisions — no energy quanta assumed.** Particles bounce in a walled cavity. The frequency histogram converges to the Planck distribution. No discrete energy quanta, no Planck's constant inserted — the quantization is a consequence of the discrete pixel/tick lattice. Classically this is supposed to produce the Rayleigh-Jeans divergence (infinite energy at high frequencies); the discrete lattice cuts it off and yields the Planck curve instead. *New to FRQTL? Start with **Hello, FRQTL** (`getting-started-hello-frqtl`) for the `caps.frqtl` setup-module + declarative-canvas basics this notebook assumes.* Bounce-walled oven cavity with thermostat — editable user code: /* setupBlackbody — THIN ADAPTER over the canonical setup factory * (WS gym-controls-as-sugar Bite 0: this cell used to hand-copy the physics — * a divergent fork of lib/frqtl/objects/setup/setupBlackbody.js that had * already drifted onto a stale `universe.init(...)` positional-argument call the * engine now FAIL-LOUDs on. The canonical factory is imported by BARE SPECIFIER * (a relative path here would 404 — see lib/shim/notebook/frqtl-setups-importmap.js); * this cell only bridges the notebook builder's `(frqtl, universe, options)` call * shape to the factory's `(universe, options)` shape — ZERO physics here.) */ import { setupBlackbody as _setupBlackbody } from '@frqtl/setups/blackbody'; export function setupBlackbody(frqtl, universe, options) { return _setupBlackbody(universe, options); } Declare a canvas that runs it. `setup="#"` + `stage`/`seed`; the shim synthesizes and runs the builder boilerplate in the realm. Click **Run** (or **Run All**): ## What you are seeing Particles bounce within the cavity, exchanging momentum on every collision. Energy redistributes across the population until the frequency distribution stabilizes — the emergent shape matches the Planck curve, not the diverging Rayleigh-Jeans prediction. **`temperature` is the driving knob.** It sets the thermostat's target `activeQuanta` count. The thermostat emits `floor((temperature - activeQuanta) / 4)` new leaf Frames per emitter per tick until the target is met, then silences all emitters that tick — a discrete proportional controller over quanta count. Raising `temperature` 300 → 4000 densifies the cavity from sparse scattered leaf dots to a near-saturated mass, increases compound-frame (non-leaf, merged) formation dramatically, and widens the escaped-radiation stream through the slit in both volume and angular spread. The captured sweep is in [`docs/internal/physics-lab/blackbody-temperature.md`](../../docs/internal/physics-lab/blackbody-temperature.md). Note: `temperature` is NOT energy or kinetic temperature in the continuous-mechanics sense — it is the integer target for `universe.activeQuanta`. The per-Frame oscillation wavelength (`wavelength = floor((capacity / mass) × WAVELENGTH_CONSTANT)`, Core Axiom §6) is unchanged by `temperature` directly; it is determined by the mass of each Frame, which grows as frames merge via collisions. Higher temperature → more collisions → larger compound frames → shorter oscillation wavelengths — the FRAQTL analog of Wien's displacement. **Edit the physics:** open the `./setups/blackbody.js` tab and pass an option override to the canonical factory — e.g. change the adapter's `_setupBlackbody(universe, options)` call to `_setupBlackbody(universe, Object.assign({ temperature: 3000 }, options))` (also try `boxFraction` or `slitHeight`) — then re-Run. The emergent frequency spectrum changes because you edited the construction, not a label. (The physics body itself lives in the canonical `lib/frqtl/objects/setup/setupBlackbody.js` — this cell is a thin, engine-agnostic adapter over it, so every other notebook and experiment page drives the SAME construction.) The simulation runs live in your browser on the compiled FRQTL (WASM) engine.