Buscando emisora…

Frecuencia 100,4 MHz

En esta frecuencia no emite nadie.

La página que buscas se ha quedado sin señal. Gira el dial o vuelve al inicio, que ahí siempre hay programa.

Volver al inicio
HTML + CSS404

Vintage radio 404

A wooden radio with an FM scale, a magic eye and static: drag the dial, and on 100.4 only the 404 noise plays.

Settings

1x

Code

<!doctype html>
<html lang="es">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="robots" content="noindex" />
    <title>404 · Page not found</title>
    <style>
      body { margin: 0; background: #000; }
      .n4-radio {
        --accent: #ffb347;
        --k: 1;
        position: fixed;
        inset: 0;
        z-index: 0;
        overflow: hidden;
        container-type: size;
        display: grid;
        place-items: center;
        background: #000;
        color: #f5f5f7;
        font-family: -apple-system,BlinkMacSystemFont,"SF Pro Display","Inter","Segoe UI",system-ui,sans-serif;
        -webkit-font-smoothing: antialiased;
        text-align: center;
        line-height: 1.4;
      }
      
      .n4-radio *,.n4-radio *::before,.n4-radio *::after {
        box-sizing: border-box;
      }
      
      .n4-radio .n4-copy {
        position: relative;
        z-index: 5;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1.6cqmin;
        width: 100%;
        max-width: 680px;
        padding: 0 6cqw;
      }
      
      .n4-radio .n4-title {
        margin: 0;
        font-size: clamp(17px,4.2cqmin,36px);
        font-weight: 600;
        letter-spacing: -.02em;
        line-height: 1.15;
        text-wrap: balance;
      }
      
      .n4-radio .n4-sub {
        margin: 0;
        max-width: 34em;
        font-size: clamp(13px,2.4cqmin,18px);
        color: #a1a1a6;
        text-wrap: balance;
      }
      
      .n4-radio .n4-tag {
        font: 600 clamp(10px,1.9cqmin,13px)/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
        letter-spacing: .16em;
        text-transform: uppercase;
        color: var(--accent);
      }
      
      .n4-radio .n4-cta {
        margin-top: 1.8cqmin;
        display: inline-flex;
        align-items: center;
        gap: .5em;
        padding: .85em 1.5em;
        border-radius: 999px;
        background: #f5f5f7;
        color: #000;
        font-size: clamp(13px,2.2cqmin,16px);
        font-weight: 600;
        text-decoration: none;
        transition: transform .3s cubic-bezier(.25,.1,.25,1),box-shadow .3s cubic-bezier(.25,.1,.25,1);
      }
      
      .n4-radio .n4-cta:hover {
        transform: translateY(-2px);
        box-shadow: 0 12px 32px -10px var(--accent);
      }
      
      .n4-radio .n4-cta:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 3px;
      }
      
      .n4-radio .n4-stars,.n4-radio .n4-stars2 {
        position: absolute;
        inset: -4%;
        pointer-events: none;
      }
      
      .n4-radio .n4-stars {
        background-image: radial-gradient(1px 1px at 8% 12%,#fff 60%,transparent),radial-gradient(1px 1px at 22% 68%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 35% 24%,#fff 60%,transparent),radial-gradient(1px 1px at 48% 82%,#fff 60%,transparent),radial-gradient(1px 1px at 57% 9%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 66% 44%,#fff 60%,transparent),radial-gradient(1px 1px at 74% 72%,#fff 60%,transparent),radial-gradient(1px 1px at 86% 18%,#fff 60%,transparent),radial-gradient(1.5px 1.5px at 93% 58%,#fff 60%,transparent),radial-gradient(1px 1px at 14% 42%,#fff 60%,transparent),radial-gradient(1px 1px at 40% 55%,#fff 60%,transparent),radial-gradient(1px 1px at 81% 90%,#fff 60%,transparent),radial-gradient(1px 1px at 4% 88%,#fff 60%,transparent),radial-gradient(1px 1px at 62% 30%,#fff 60%,transparent);
        opacity: .75;
        animation: n4-radio-tw calc(5s / var(--k)) ease-in-out infinite alternate;
      }
      
      .n4-radio .n4-stars2 {
        background-image: radial-gradient(2px 2px at 18% 30%,rgba(255,255,255,.9) 50%,transparent),radial-gradient(1.5px 1.5px at 72% 20%,rgba(255,255,255,.8) 50%,transparent),radial-gradient(2px 2px at 30% 85%,rgba(255,255,255,.7) 50%,transparent),radial-gradient(1.5px 1.5px at 88% 70%,rgba(255,255,255,.8) 50%,transparent),radial-gradient(2px 2px at 52% 60%,rgba(255,255,255,.6) 50%,transparent),radial-gradient(1.5px 1.5px at 6% 55%,rgba(255,255,255,.8) 50%,transparent);
        opacity: .55;
        animation: n4-radio-tw calc(7s / var(--k)) ease-in-out infinite alternate-reverse;
      }
      
      .n4-radio [data-depth] {
        transition: transform .9s cubic-bezier(.2,.7,.2,1);
      }
      
      @keyframes n4-radio-tw {
        from {
          opacity: .3;
        }
      }
      
      @keyframes n4-radio-spin {
        to {
          transform: rotate(1turn);
        }
      }
      
      @keyframes n4-radio-fade {
        from {
          opacity: 0;
          transform: translateY(10px);
        }
      }
      
      @media (prefers-reduced-motion:reduce) {
        .n4-radio *,.n4-radio *::before,.n4-radio *::after {
          animation: none!important;
          transition: none!important;
        }
      }
      
      .n4-radio {
        background: radial-gradient(70% 60% at 50% 30%,#3d2b1d,#140d08 75%);
        color: #f7ead2;
      }
      
      .n4-radio .n4-set {
        --v: 0;
        --sig: 0;
        --noise: 1;
        width: min(64cqmin,450px);
        font-size: min(2cqmin,14px);
        margin-bottom: 1.6cqmin;
        padding: 1.5em 1.6em 1.1em;
        border-radius: 5em 5em 1.2em 1.2em/3.4em 3.4em 1.2em 1.2em;
        background: repeating-linear-gradient(93deg,rgba(0,0,0,.07) 0 .25em,transparent .25em .9em,rgba(255,220,180,.04) .9em 1.2em,transparent 1.2em 2em),linear-gradient(160deg,#8f4f25,#5a2d12 60%,#3b1d0a);
        box-shadow: inset 0 .25em .3em rgba(255,255,255,.2),inset 0 -.5em .8em rgba(0,0,0,.45),0 2em 3em -1.4em #000;
      }
      
      .n4-radio .n4-top {
        display: flex;
        gap: 1.2em;
        height: 8.5em;
      }
      
      .n4-radio .n4-grille {
        position: relative;
        flex: 1;
        overflow: hidden;
        border-radius: 2.6em 2.6em .6em .6em;
        background: repeating-linear-gradient(90deg,transparent 0 1.6em,#4a240d 1.6em 2em),repeating-linear-gradient(45deg,rgba(0,0,0,.2) 0 1px,transparent 1px 3px),repeating-linear-gradient(-45deg,rgba(0,0,0,.2) 0 1px,transparent 1px 3px),#cdb68a;
        box-shadow: inset 0 0 0 .3em #3b1d0a,inset 0 0 1.4em rgba(0,0,0,.5);
      }
      
      .n4-radio .n4-on .n4-grille {
        animation: n4-radio-thump calc(.45s / var(--k)) ease-in-out infinite alternate;
      }
      
      .n4-radio .n4-static {
        position: absolute;
        inset: -10px;
        opacity: var(--noise);
        background: repeating-radial-gradient(circle at 27% 38%,rgba(255,255,255,.55) 0 1px,transparent 1px 3px),repeating-radial-gradient(circle at 71% 63%,rgba(0,0,0,.45) 0 1px,transparent 1px 4px);
        animation: n4-radio-noise calc(.18s / var(--k)) steps(3) infinite;
      }
      
      .n4-radio .n4-side {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: space-between;
        width: 5.4em;
      }
      
      .n4-radio .n4-eye {
        width: 3.6em;
        height: 3.6em;
        border-radius: 50%;
        background: radial-gradient(circle,#0b1a10 0 22%,transparent 23%),conic-gradient(from calc(180deg - var(--uvq17-w)),#0b1a10 0 calc(var(--uvq17-w) * 2),#6dff8a 0);
        --uvq17-w: calc((1 - var(--sig)) * 70deg + 4deg);
        box-shadow: 0 0 0 .35em #2a160a,0 0 0 .5em #b78a4a,0 0 1.2em rgba(109,255,138,calc(var(--sig) * .7));
        transition: --uvq17-w .2s;
      }
      
      .n4-radio .n4-knob {
        width: 2.6em;
        height: 2.6em;
        border-radius: 50%;
        background: repeating-conic-gradient(#e9d8b4 0 8deg,#b99b66 8deg 16deg);
        box-shadow: inset 0 0 0 .5em #f3e6c8,0 .2em .3em rgba(0,0,0,.5);
        rotate: calc(var(--v) * 3.6deg);
      }
      
      .n4-radio .n4-k2 {
        rotate: calc(var(--v) * -1.2deg);
      }
      
      .n4-radio .n4-scale {
        position: relative;
        height: 3.2em;
        margin-top: 1.1em;
        border-radius: .5em;
        cursor: ew-resize;
        touch-action: none;
        background: linear-gradient(#f6e7bf,#e2c98d);
        box-shadow: inset 0 0 0 .2em #3b1d0a,inset 0 0 1.6em rgba(255,170,60,.55);
      }
      
      .n4-radio .n4-scale:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 3px;
      }
      
      .n4-radio .n4-track {
        position: absolute;
        inset: 0 6%;
        background: repeating-linear-gradient(90deg,#3b1d0a 0 1px,transparent 1px 2%) 0 100%/100% 28% no-repeat;
      }
      
      .n4-radio .n4-nums b {
        position: absolute;
        top: .35em;
        left: calc(var(--p) * 1%);
        translate: -50% 0;
        font: 700 .95em/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
        color: #3b1d0a;
      }
      
      .n4-radio .n4-needle {
        position: absolute;
        top: .25em;
        bottom: .25em;
        left: calc(var(--v) * 1%);
        width: .2em;
        margin-left: -.1em;
        border-radius: .1em;
        background: #d7261e;
        box-shadow: 0 0 .4em rgba(215,38,30,.6);
      }
      
      .n4-radio .n4-station {
        min-height: 1.3em;
        margin: .7em 0 0;
        font: 600 1em/1.3 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
        letter-spacing: .04em;
        color: #f6e7bf;
      }
      
      .n4-radio .n4-tag {
        color: var(--accent);
      }
      
      .n4-radio .n4-title {
        font-size: clamp(20px,5cqmin,42px);
        font-weight: 700;
        letter-spacing: -.025em;
      }
      
      .n4-radio .n4-sub {
        color: #cdb79b;
      }
      
      .n4-radio .n4-cta {
        background: var(--accent);
        color: #2a1406;
      }
      
      @property --uvq17-w {
        syntax: "<angle>";
        inherits: true;
        initial-value: 74deg;
      }
      
      @keyframes n4-radio-noise {
        33% {
          background-position: 3px 1px,-2px 3px;
        }
        66% {
          background-position: -1px -3px,2px -1px;
        }
      }
      
      @keyframes n4-radio-thump {
        to {
          transform: scale(1.012);
        }
      }
    </style>
  </head>
  <body>
    <main class="n4-radio">
      <div class="n4-copy">
        <div class="n4-set">
          <div class="n4-top" aria-hidden="true">
            <div class="n4-grille"><i class="n4-static"></i></div>
            <div class="n4-side"><i class="n4-eye"></i><i class="n4-knob"></i><i class="n4-knob n4-k2"></i></div>
          </div>
          <div class="n4-scale" role="slider" tabindex="0" aria-label="Tuning dial" aria-valuemin="880" aria-valuemax="1080" aria-valuenow="880" aria-valuetext="88,0 MHz">
            <div class="n4-track"><span class="n4-nums" aria-hidden="true" translate="no"><b style="--p:0">88</b><b style="--p:20">92</b><b style="--p:40">96</b><b style="--p:60">100</b><b style="--p:80">104</b><b style="--p:100">108</b></span><i class="n4-needle" aria-hidden="true"></i></div>
          </div>
          <p class="n4-station" aria-live="polite">Searching for a station…</p>
        </div>
        <span class="n4-tag">Frequency 100.4 MHz</span>
        <h1 class="n4-title">Nobody broadcasts on this frequency.</h1>
        <p class="n4-sub">The page you're looking for has lost its signal. Turn the dial or go back home, there's always something on there.</p>
        <a class="n4-cta" href="/">Back to home</a>
      </div>
    </main>
    <script>
      document.querySelectorAll(".n4-radio").forEach((el) => {
        const set = el.querySelector(".n4-set");
        const scale = el.querySelector(".n4-scale");
        const track = el.querySelector(".n4-track");
        const label = el.querySelector(".n4-station");
        const rm = matchMedia("(prefers-reduced-motion: reduce)").matches;
        const k = parseFloat(getComputedStyle(el).getPropertyValue("--k")) || 1;
        const ST = [[914, "Onda Jazz"], [965, "24 hour news"], [1004, "404 FM: broadcast not found"], [1052, "Late night boleros"]];
        const SEARCH = "Searching for a station…";
        let v = 880, shown = SEARCH, raf = 0;
        const render = () => {
          let best = 0, name = SEARCH, lost = false;
          for (const [f, n] of ST) {
            const s = Math.max(0, 1 - Math.abs(v - f) / 10);
            if (s > best) { best = s; if (s > 0.55) { name = n; lost = f === 1004; } }
          }
          set.style.setProperty("--v", ((v - 880) / 2).toFixed(2));
          set.style.setProperty("--sig", best.toFixed(2));
          set.style.setProperty("--noise", (lost ? 0.75 : 1 - best * 0.9).toFixed(2));
          set.classList.toggle("n4-on", best > 0.55 && !lost);
          scale.setAttribute("aria-valuenow", String(v));
          scale.setAttribute("aria-valuetext", (v / 10).toFixed(1).replace(".", ",") + " MHz");
          if (name !== shown) { shown = name; label.textContent = name; }
        };
        const tune = (n) => { cancelAnimationFrame(raf); v = Math.max(880, Math.min(1080, Math.round(n))); render(); };
        const fromX = (e) => { const r = track.getBoundingClientRect(); tune(880 + ((e.clientX - r.left) / r.width) * 200); };
        let down = false;
        scale.addEventListener("pointerdown", (e) => { down = true; scale.setPointerCapture(e.pointerId); fromX(e); });
        scale.addEventListener("pointermove", (e) => { if (down) fromX(e); });
        scale.addEventListener("pointerup", () => { down = false; });
        scale.addEventListener("pointercancel", () => { down = false; });
        scale.addEventListener("keydown", (e) => {
          const d = { ArrowRight: 1, ArrowUp: 1, ArrowLeft: -1, ArrowDown: -1, PageUp: 10, PageDown: -10 }[e.key];
          if (d) { e.preventDefault(); tune(v + d); }
          else if (e.key === "Home") { e.preventDefault(); tune(880); }
          else if (e.key === "End") { e.preventDefault(); tune(1080); }
        });
        const t0 = performance.now();
        const sweep = (t) => {
          const p = Math.min(1, (t - t0) / (2400 / k));
          v = Math.round(880 + 124 * (1 - Math.pow(1 - p, 3)));
          render();
          if (p < 1) raf = requestAnimationFrame(sweep);
        };
        if (rm) { v = 1004; render(); } else raf = requestAnimationFrame(sweep);
      });
    </script>
  </body>
</html>

Prompt for AI

Paste it into ChatGPT, Claude or Cursor and it will adapt the block to your project with these settings, even if you don’t use React.

Markdown version with all the code, for AI assistants

More in 404

See all 404

Where to use it

This error page is a walnut tabletop radio with a cloth speaker grille, a green magic eye tuning tube and a backlit FM scale. On load the red needle sweeps up the band; drag the scale or use the arrow keys to tune, and the eye opens as you approach a station while the static fades.

Most stations play and the grille gently pulses, but 404 FM on 100.4 has a perfect signal and nothing on air. The scale is an accessible slider that reads the frequency aloud. Adjust the amber accent and the speed.