How a chip is printed — an isometric fab that runs real diffraction physics in your browser.
An interactive explainer for semiconductor photolithography. A wafer travels a ring road, and one lap is one mask layer: a blank film goes on, resist is spun and baked, the scanner turns a mask into an image in that resist, the image is developed into a physical pattern, and the etch bay cuts it into the film underneath. Then the resist burns off and the wafer comes round again. A real logic chip needs sixty to eighty laps.
No build step, no dependencies, no network calls. Open index.html and it runs.
Almost everything strange about modern chipmaking — immersion scanners, multi-patterning, twenty years and roughly ten billion dollars spent getting EUV to work — is a response to one wall:
A grating splits light into diffraction orders at angles set by its pitch. The lens catches whatever falls inside its numerical aperture and throws the rest away. An image built from too few orders is not a faint pattern — it is no pattern at all.
This page computes that, rather than asserting it. Drag the half-pitch down and watch the side orders walk off the edge of the lens in the Scanner, the aerial image go flat, and the wafer come out blank.
Nothing in the code enforces the famous k₁ = 0.25 floor. It is never written down as a
rule. It emerges because below it the ±1 orders physically cannot both fit through the
pupil. The same code reproduces the partial-coherence limit k₁ = 0.5/(1+σ) for
conventional illumination without being told about that either. Those two facts are the
reason the interesting parts of this page can be trusted.
| Try this | Because |
|---|---|
| EUV, drag half-pitch below 13 nm | The side orders miss the lens. This is the wall, to scale. |
| Then switch NA to 0.55 | High-NA EUV rescues it — and look what happened to depth of focus. |
| ArF + immersion, reach 10 nm half-pitch | Single exposure fails; quad patterning gets there, at 4× the masks, scanner time and overlay error. That trade is why EUV exists. |
| Conventional vs dipole at a tight pitch | Nothing about the lens changed. Only the angle the light arrives at. |
| Drag defocus with dipole, then with annular | Symmetric two-beam imaging is nearly focus-free. Lopsided orders are not. |
| Drop dose at a small feature | Read the photon count, then the stochastic failure rate. |
| Annular + 200 nm defocus | The inspection fails and the wafer takes the rework spur. It is not scripted. |
Between develop and etch the wafer is inspected. If the pattern is out of spec the resist is stripped and the wafer goes back to the coater — the road cutting across the middle of the ring. Once the pattern is etched, that option is gone.
The verdict is computed, not rolled. Sim.judge() reads the model: is k₁ under the
floor, did anything print, is NILS below 1.5, is the linewidth more than 15% off target,
will the lines collapse in the rinse. Push a control far enough and the wafer genuinely
fails, genuinely reworks, and after two attempts is genuinely scrapped. A reworked wafer
re-enters at the coater, never at the film yard — it does not get a second film deposited
on it.
Half the value of a page like this is knowing which numbers to trust.
All in js/model.js.
The aerial image, by Abbe's method. The mask is Fourier-decomposed into diffraction
orders — the coefficients of a binary grating are exactly duty · sinc(m · duty). Every
point in the illuminator is imaged separately. Each order is placed in the pupil at
direction cosine m·λ/pitch offset by its source point, and discarded if it falls outside
the numerical aperture. The survivors are summed as a coherent field; the intensities of
all source points are added. Defocus is a real optical path difference,
z(n − √(n² − α²)), applied per order — which is why it hurts high orders more than low
ones, and small pitches more than large ones.
Then acid diffusion blurs it (circular Gaussian convolution), a threshold develops it, and the linewidth and NILS are measured off the result by interpolated threshold crossing.
Also computed: Rayleigh resolution and depth of focus, with the immersion index in the right places; photon energy from Planck and the shot-noise statistics that follow; the Gaussian tail (evaluated asymptotically, because the interesting probabilities are past 1e-12) that gives the stochastic failure rate; Murphy's yield model; overlay and edge placement error as root-sum-square; the exposure field count, by actually tiling a 300 mm wafer; and dose-limited versus stage-limited throughput.
node test-model.mjs checks the model against published numbers — ArF immersion bottoming
out at 38 nm half-pitch, EUV 0.33 NA at 13 nm, high-NA at 8 nm, EUV photons carrying 14.3×
the energy of ArF photons, ~84 fields on a 300 mm wafer, and the two roadmap decisions
(193i quad works at 10 nm and fails at 8 nm; EUV 0.33 fails at 10 nm and 0.55 succeeds).
A one-dimensional line/space grating instead of a real two-dimensional layout. Nine diffraction orders, a 24×24 source grid, 128 image samples. A handful of mask layers instead of the sixty to eighty a real chip needs.
The resist threshold and the acid diffusion length — both proprietary and resist-specific. The etch bias. The ~3.5 aspect ratio at which lines collapse in the rinse. The split between scanner and process overlay. Every track and etch time in the time-budget panel, which are there for proportion rather than precision — only the exposure bar is derived.
Optical transmission to the wafer and the stage overheads are fitted so throughput reproduces what tool vendors publish: ~160 wafers/hour for EUV at 30 mJ/cm², ~275 for ArF immersion. An EUV beam really does lose almost all its energy on the way to the wafer (ten-odd multilayer mirrors at ~70% each), so a sub-1% figure is the right order — but the exact value is a fit, not a measurement.
Tool and mask prices are the publicly reported ones; everything about how a fab amortises them is invented. Treat the cost figure as a ratio between technologies, not a quote.
Resolution enhancement beyond the shape of the illuminator. There is no optical proximity correction, no sub-resolution assist features, no phase-shift masks, no mask three-dimensional effects, no source-mask co-optimisation. Real advanced layers depend on all of these, and a real 8 nm half-pitch would not print from the bare geometry this model exposes.
Treat the fab as an illustration and the optics as the lesson.
One lap of the ring is one mask layer.
| Station | What it does | What the model computes |
|---|---|---|
| Film Yard | Deposits the blank film to be patterned | — |
| Coat Track | Spins on photoresist | resist thickness → aspect ratio |
| Bake Ovens | Drives off solvent | — |
| Alignment Bay | Aligns to the previous layer | overlay, edge placement error |
| Illuminator Hall | Shapes the source | the pupil the image is integrated over |
| The Scanner | Mask → aerial image | Abbe imaging, diffraction orders, defocus |
| PEB Ovens | Chemical amplification | acid diffusion blur |
| Develop Track | Image → physical pattern | CD and NILS by threshold crossing |
| Inspection | Pass, or back to the coater | the branch verdict |
| Etch Bay | Pattern into the film | etch bias, collapse check |
| Ash Hall | Burns off the resist | — |
| Metrology Hall | Measures what shipped | stochastic defects, yield |
| Rework Bay | Strips and returns to the coater | (spur only) |
index.html markup, controls, the About modal with the fidelity ledger
css/styles.css light print-like UI: full-screen canvas, floating panels
js/iso.js ENGINE. Projection, solids, routes.
js/model.js THE LESSON. The real simulation — start here.
js/world.js the fab floor: ring road, rework spur, stations, landmarks
js/sim.js ENGINE. State machine: travel, stations, reading stops, the branch
js/render.js one sorted painter's pass over everything with a footprint
js/ui.js DOM panels, the aerial-image plot, narration, controls
js/main.js ENGINE. Camera, input, frame loop.
python3 -m http.server 8000 # or just open index.html
node test-model.mjs # physics vs published numbers, no browser needed
npm i -D playwright && npx playwright install chromium
node smoke.mjs http://localhost:8000/ # every station fires, no console errors
node test-fab.mjs # layout, the wall, the rework branch, mobileSpace play/pause · S one station · R reset and replay the tour · F follow camera · L labels. Drag to pan, scroll to zoom, click any station for its write-up, double-click or ⤢ to see the whole fab.
The first visit to a station stops long enough to read its write-up. Later layers run at a watchable pace instead of a readable one. Reset replays the slow tour; Run keeps what you have already read.
Built with the isometric-explainer skill. All code and copy original. MIT.