Introduction

Touch a copper wire to a battery and current flows. Touch a glass rod and nothing happens. Both are built from atoms, both have electrons — so why does one conduct and the other insulate?

The answer is not about the number of electrons. It is about the energy levels those electrons are allowed to occupy. In a crystal, atoms arrange themselves in a perfectly periodic lattice. That periodicity does something remarkable to the quantum mechanics of every electron inside: it forces the allowed energies to clump into bands, separated by gaps where no electron can exist.

Whether a material's highest occupied electrons sit inside a band or right at the edge of a gap decides everything: conductor, insulator, or the in-between state that makes semiconductors — and therefore all of modern electronics — possible.

Tune the Gap

The slider below controls the strength of the periodic crystal potential V0V_0. When V0=0V_0 = 0 electrons are free and their energies form a continuous parabola. As you increase V0V_0 the lattice scatters electrons and forbidden gaps open at the zone boundaries.

<!-- Band structure demo — nearly-free electron model -->
<div class="controls">
  <label>
    <span class="lbl">Potential strength V₀</span>
    <input id="potSlider" type="range" min="0" max="100" value="0" step="1">
    <span id="potVal" class="val">0</span>
  </label>
  <label>
    <span class="lbl">Electron fill (band fraction)</span>
    <input id="fillSlider" type="range" min="0" max="2" value="1" step="0.01">
    <span id="fillVal" class="val">1.00</span>
  </label>
</div>
<canvas id="canvas" width="480" height="280" aria-label="Energy band diagram showing allowed bands and forbidden gaps"></canvas>
<div id="material" class="material-label"></div>
<div class="legend">
  <span class="dot dot-band"></span> Allowed band
  <span class="dot dot-gap"></span> Forbidden gap
  <span class="dot dot-fermi"></span> Fermi level
</div>
/* Styles for the band-structure interactive demo */
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; margin: 0; background: #f7f9fb; color: #1d2d3e; }
.controls { display: flex; flex-direction: column; gap: .5rem; padding: .6rem .8rem .2rem; }
label { display: flex; align-items: center; gap: .5rem; font-size: .88rem; }
.lbl { width: 10rem; flex-shrink: 0; }
input[type=range] { flex: 1; accent-color: #1d6fa4; }
.val { width: 2.8rem; text-align: right; font-variant-numeric: tabular-nums; font-size: .88rem; }
canvas { display: block; margin: .3rem auto 0; border-radius: 8px;
         background: #fff; box-shadow: 0 1px 4px rgba(0,0,0,.12); }
.material-label { text-align: center; font-size: 1rem; font-weight: 700;
                  min-height: 1.6em; margin: .35rem 0 .1rem; letter-spacing: .02em; }
.material-label.metal { color: #b8860b; }
.material-label.semi  { color: #1d6fa4; }
.material-label.ins   { color: #c0392b; }
.legend { display: flex; align-items: center; gap: 1rem; justify-content: center;
          font-size: .8rem; color: #555; padding: .15rem 0 .4rem; flex-wrap: wrap; }
.dot { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: .2rem; }
.dot-band  { background: #1d6fa4; }
.dot-gap   { background: #fce4d6; border: 1px solid #e8967a; }
.dot-fermi { background: #e05c2b; height: 3px; border-radius: 1px; width: 18px; }
/* Nearly-free electron model band structure visualizer */
const i18nFmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const potSlider = document.getElementById('potSlider');
const fillSlider = document.getElementById('fillSlider');
const potValEl = document.getElementById('potVal');
const fillValEl = document.getElementById('fillVal');
const materialEl = document.getElementById('material');

/* Canvas geometry constants */
const W = canvas.width, H = canvas.height;
const PAD = { l: 48, r: 16, t: 20, b: 28 };
const plotW = W - PAD.l - PAD.r;
const plotH = H - PAD.t - PAD.b;

/* Compute band energies using the 2x2 nearly-free-electron model */
function bandEnergies(k, V0) {
  /* Two parabolas coupled by the periodic potential V0 */
  const hbar2_2m = 1.0; // energy units set so hbar2/2m = 1
  const G = 2 * Math.PI; // first reciprocal lattice vector (2*pi/a, with a=1)
  /* free-electron energies for k and k-G (folded into first Brillouin zone) */
  const E0_minus = hbar2_2m * Math.pow(k - G, 2);
  const E0_plus  = hbar2_2m * Math.pow(k, 2);
  const E0_plus2 = hbar2_2m * Math.pow(k + G, 2);
  const E0_minus2 = hbar2_2m * Math.pow(k - 2*G, 2);
  /* 2x2 degenerate perturbation theory — E = avg +/- sqrt(delta2 + V02) */
  const avg1 = (E0_minus + E0_plus) / 2;
  const gap1 = Math.sqrt(Math.pow((E0_minus - E0_plus)/2, 2) + V0*V0);
  const E1 = avg1 - gap1;
  const E2 = avg1 + gap1;
  const avg2 = (E0_plus2 + E0_plus) / 2;
  const gap2 = Math.sqrt(Math.pow((E0_plus2 - E0_plus)/2, 2) + V0*V0);
  const E3 = avg2 - gap2;
  const E4 = avg2 + gap2;
  const avg3 = (E0_minus2 + E0_minus) / 2;
  const gap3 = Math.sqrt(Math.pow((E0_minus2 - E0_minus)/2, 2) + V0*V0);
  const E5 = avg3 - gap3;
  return [E1, E2, E3, E4, E5];
}

function getV0() {
  return parseFloat(potSlider.value) / 100 * 0.8;
}

function getFillFraction() {
  return parseFloat(fillSlider.value);
}

/* Main draw function — called on every slider change */
function draw() {
  ctx.clearRect(0, 0, W, H);
  const V0 = getV0();
  const fill = getFillFraction();

  /* Sample the full first Brillouin zone */
  const NK = 200;
  const kMin = -Math.PI, kMax = Math.PI;
  const bands = [[], [], [], [], []];
  for (let i = 0; i <= NK; i++) {
    const k = kMin + (kMax - kMin) * i / NK;
    const en = bandEnergies(k, V0);
    for (let b = 0; b < 5; b++) bands[b].push({ k, e: en[b] });
  }

  /* Find energy range for scaling the y-axis */
  let eMin = Infinity, eMax = -Infinity;
  for (const band of bands) for (const p of band) {
    if (p.e < eMin) eMin = p.e;
    if (p.e > eMax) eMax = p.e;
  }
  const ePad = (eMax - eMin) * 0.05;
  eMin -= ePad; eMax += ePad;

  const toX = (k) => PAD.l + (k - kMin) / (kMax - kMin) * plotW;
  const toY = (e) => PAD.t + (1 - (e - eMin) / (eMax - eMin)) * plotH;

  /* Shade the first forbidden gap between band 1 and band 2 */
  if (V0 > 0.01) {
    const gapTop = bands[1].reduce((mn, p) => Math.min(mn, p.e), Infinity);
    const gapBot = bands[0].reduce((mx, p) => Math.max(mx, p.e), -Infinity);
    if (gapTop > gapBot) {
      const y1 = toY(gapTop), y2 = toY(gapBot);
      ctx.fillStyle = 'rgba(252,228,214,0.75)';
      ctx.fillRect(PAD.l, y1, plotW, y2 - y1);
      ctx.strokeStyle = '#e8967a';
      ctx.lineWidth = 0.8;
      ctx.setLineDash([4, 3]);
      ctx.beginPath(); ctx.moveTo(PAD.l, y1); ctx.lineTo(PAD.l + plotW, y1); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(PAD.l, y2); ctx.lineTo(PAD.l + plotW, y2); ctx.stroke();
      ctx.setLineDash([]);
    }
  }

  /* Draw axes and k-point labels */
  ctx.strokeStyle = '#bbb'; ctx.lineWidth = 1; ctx.setLineDash([]);
  ctx.beginPath();
  ctx.moveTo(PAD.l, PAD.t); ctx.lineTo(PAD.l, PAD.t + plotH);
  ctx.moveTo(PAD.l, PAD.t + plotH); ctx.lineTo(PAD.l + plotW, PAD.t + plotH);
  ctx.stroke();
  ctx.fillStyle = '#888'; ctx.font = '11px system-ui';
  ctx.textAlign = 'center';
  ctx.fillText('-π/a', toX(kMin), PAD.t + plotH + 16);
  ctx.fillText('0', toX(0), PAD.t + plotH + 16);
  ctx.fillText('+π/a', toX(kMax), PAD.t + plotH + 16);
  ctx.textAlign = 'right';
  ctx.fillText('E', PAD.l - 4, PAD.t + 6);
  ctx.textAlign = 'left';

  /* Draw each energy band as a colored curve */
  const colors = ['#1d6fa4', '#2e8b57', '#7b2d8b', '#b8860b', '#555'];
  for (let b = 0; b < 5; b++) {
    ctx.beginPath();
    ctx.strokeStyle = colors[b % colors.length];
    ctx.lineWidth = 2;
    for (let i = 0; i < bands[b].length; i++) {
      const { k, e } = bands[b][i];
      const x = toX(k), y = toY(e);
      i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
    }
    ctx.stroke();
  }

  /* Draw the Fermi level at the fill fraction of all sampled states */
  const allE = bands.flat().map(p => p.e).sort((a, b) => a - b);
  const fermiIdx = Math.floor(fill * (allE.length - 1));
  const fermiE = allE[Math.max(0, Math.min(fermiIdx, allE.length - 1))];
  const yF = toY(fermiE);
  ctx.strokeStyle = '#e05c2b'; ctx.lineWidth = 2; ctx.setLineDash([6, 4]);
  ctx.beginPath(); ctx.moveTo(PAD.l, yF); ctx.lineTo(PAD.l + plotW, yF); ctx.stroke();
  ctx.setLineDash([]);

  /* Classify material based on Fermi level position and gap width */
  const gapTop2 = V0 > 0.01 ? bands[1].reduce((mn, p) => Math.min(mn, p.e), Infinity) : null;
  const gapBot2 = V0 > 0.01 ? bands[0].reduce((mx, p) => Math.max(mx, p.e), -Infinity) : null;
  const inGap = gapTop2 !== null && fermiE > gapBot2 && fermiE < gapTop2;
  const gapWidth = (gapTop2 !== null && V0 > 0.01) ? (gapTop2 - gapBot2) : 0;
  let matClass = 'metal', matText;
  if (V0 < 0.01) {
    matText = i18nFmt('Free electrons — no gap (not a real crystal)', {});
  } else if (inGap && gapWidth > 0.3) {
    matClass = 'ins'; matText = i18nFmt('Insulator — Fermi level sits inside a large gap', {});
  } else if (inGap && gapWidth <= 0.3) {
    matClass = 'semi'; matText = i18nFmt('Semiconductor — Fermi level sits inside a small gap', {});
  } else {
    matClass = 'metal'; matText = i18nFmt('Metal — Fermi level inside a band', {});
  }
  materialEl.className = 'material-label ' + matClass;
  materialEl.textContent = matText;
}

potSlider.addEventListener('input', () => {
  potValEl.textContent = potSlider.value;
  draw();
});
fillSlider.addEventListener('input', () => {
  fillValEl.textContent = parseFloat(fillSlider.value).toFixed(2);
  draw();
});

draw();
Result
Console

Watch how the first gap (between the first and second band) widens as the potential grows. The Fermi level line shows where electrons fill up to at absolute zero. Drag it into a gap and you have an insulator or semiconductor; leave it inside a band and you have a metal.

The Real Physics

How does a regular lattice carve continuous energies into bands and gaps?

  • Free electrons have energies E=ℏ2k2/2mE = \hbar^2 k^2 / 2m — a smooth parabola in momentum kk.
  • Bloch's theorem (Felix Bloch, 1928) says that in any periodic potential an electron wave function must take the form ψk(x)=eikxuk(x)\psi_k(x) = e^{ikx} u_k(x), where uku_k shares the lattice period. This is exact, not an approximation.
  • Gaps open at zone boundaries. When the electron's wavelength satisfies 2dsin⁡θ=nλ2d\sin\theta = n\lambda (the Bragg condition for the lattice spacing dd), the lattice reflects the wave perfectly. The forward and backward waves combine into two standing waves with different energies — and that energy difference is the band gap.
  • Gap size scales with potential strength. In the nearly-free-electron model the gap at the first zone boundary equals 2∣V1∣2|V_1|, where V1V_1 is the first Fourier coefficient of the periodic potential. A weak potential means a small gap (semiconductor); a strong one means a large gap (insulator).
  • Metals, semiconductors, insulators. Fill the bands from the bottom. If the highest occupied band is partially filled, electrons can accelerate into empty nearby states — metal. If it is completely filled and the gap is large (>4 eV> 4\ \text{eV}), electrons cannot jump across — insulator. A small gap (0.10.1–3 eV3\ \text{eV}) means a semiconductor: insulating at absolute zero, conducting when thermally or optically excited.

This picture, worked out in the late 1920s by Bloch, Brillouin, and Peierls, explained for the first time why the periodic table contains conductors and insulators side by side.

Where It Matters

Understanding which energy states electrons can occupy is not just elegant physics — it is the blueprint for almost every electronic device:

  • Transistors and integrated circuits: silicon sits in a sweet spot — its 1.1 eV1.1\ \text{eV} gap is small enough to be switched on and off with a gate voltage, which is why every CPU on the planet is built on it.
  • Solar cells: a photon is absorbed only if its energy exceeds the band gap. Engineers tune the gap of materials like GaAs or perovskites to match the solar spectrum and maximize efficiency.
  • LEDs and lasers: when an electron falls from the conduction band into the valence band it emits a photon whose color is fixed by the gap. Tune the gap, tune the color — that is how we get blue LEDs (GaN, 3.4 eV3.4\ \text{eV}) or infrared laser diodes.
  • Topological insulators: a material can be insulating in the bulk yet perfectly conducting on its surface because of a topological twist in the band structure — a phenomenon with no classical analogue.
  • Quantum computing: many qubit designs exploit discrete energy levels created by engineered band gaps in superconducting or semiconducting nanostructures.

Every time you charge a phone, stream a video, or take a photo, you are riding on the consequences of a periodic lattice opening a gap in an electron's energy spectrum.

Conclusion

A single idea explains the entire electrical zoo of the periodic table: periodicity creates gaps. When atoms line up in a regular lattice, quantum mechanics forces their electrons into allowed bands separated by forbidden zones. The gap between the highest filled band and the next empty one — measured in electron-volts — is the one number that determines whether you are holding a conductor, an insulator, or a semiconductor.

Engineers have spent a century learning to tune that gap: dope silicon, grow thin films of exotic alloys, stack atomic layers one at a time. The result is every transistor, every LED, every solar cell ever made. Next time you flip a light switch, remember that the reason current flows — or doesn't — is a standing electron wave bouncing off a crystal lattice, just as quantum simulation of such systems becomes one of the hardest problems in computational complexity.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/band-structure/Content licensed under CC BY-NC 4.0.