Brass Knife Switch on a Slate Base That Closes with a Spark and Lights Four Opal Lamps Spelling Live

A laboratory knife switch seen from the side, standing on a slab of slate with a row of four opal globes wired to it in blue cloth-covered flex. Each globe carries one letter of a four-letter word. Take the black grip and push the blade down, or press the button underneath: the blade falls, an arc jumps as it reaches the jaw, the jaw grips it for the last few degrees, and the lamps catch one after another with a short flicker each, throwing blue light up the wall, onto the stone and along the grip. Pull the blade out and a smaller spark follows it while the lamps fade in turn. A brass plate screwed to the front of the slate is engraved with the site's address. Everything is gradients plus one small canvas for the sparks; the stone grain is an SVG turbulence filter. On a phone the bench scales to the width of the screen and the button stays full size.

Code

import { useEffect, useRef, useState } from "react";

const LAMPS = ["L", "I", "V", "E"]; // one opal globe per letter
const site = { name: "Saltmarsh Surf School", address: "saltmarshsurf.example" };
const BLUE = "#4F98FB";
const FONT = '"Inter Tight", "Inter", ui-sans-serif, system-ui, sans-serif';

const W = 800, H = 470; // the stage everything is laid out in
const SX = 30, SW = 740; // the slate base
const TOP = 336, FACE = 364, BOT = 410; // back of its top, its front edge, its underside
const FEET = 351; // the line the fittings stand on
const PX = 356, PY = 301; // hinge pin of the blade
const BL = 188; // hinge to jaw
const JX = PX - BL;
const A_OPEN = 0.96; // how far the blade lifts, in radians
const LAMP_X = [476, 556, 636, 716];
const FIRST = 5200, OPEN_FOR = 1700, HOLD = 7600; // the demo
const BRASS = "linear-gradient(180deg,#fff2c0 0%,#e2bf68 14%,#b98d30 46%,#8a651a 78%,#4a340a 100%)";
const BRASS_X = "linear-gradient(90deg,#4f370a 0%,#a67a22 16%,#f1d587 36%,#fff4c8 44%,#d2a846 58%,#8c661a 82%,#402c07 100%)";

type Api = { set: (closed: boolean) => void };
type Bit = { x: number; y: number; vx: number; vy: number; life: number; max: number };

function Screw({ left, top, size = 9 }: { left: number; top: number; size?: number }) {
  return (
    <span className="absolute rounded-full" style={{ left, top, width: size, height: size, background: "radial-gradient(circle at 36% 30%,#fff7d6,#c79c3e 48%,#4a340a)", boxShadow: "0 1px 1px rgba(0,0,0,0.7)" }}>
      <span className="absolute left-[15%] right-[15%] top-1/2 h-[1.4px] -translate-y-1/2 rotate-[28deg] bg-[#2e2006]" />
    </span>
  );
}

export default function BrassKnifeSwitch() {
  const stage = useRef<HTMLDivElement>(null);
  const root = useRef<HTMLDivElement>(null);
  const blade = useRef<HTMLDivElement>(null);
  const grip = useRef<HTMLDivElement>(null);
  const sparks = useRef<HTMLCanvasElement>(null);
  const api = useRef<Api | null>(null);
  const [zoom, setZoom] = useState(1);
  const [live, setLive] = useState(true);

  useEffect(() => {
    const st = stage.current, el = root.current, bl = blade.current, gr = grip.current, cv = sparks.current;
    const ctx = cv?.getContext("2d");
    if (!st || !el || !bl || !gr || !cv || !ctx) return;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const dpr = Math.min(2, window.devicePixelRatio || 1);
    cv.width = 260 * dpr; cv.height = 260 * dpr;
    const scale = () => Math.max(0.4, Math.min(1.12, (st.clientWidth - 12) / W));
    const fit = () => setZoom(scale());
    fit();
    const ro = new ResizeObserver(fit);
    ro.observe(st);

    // a: angle of the blade, 0 when it is home in the jaw. The piece opens closed and lit.
    const s = { a: 0, w: 0, to: 0, drag: false, made: true, onAt: LAMPS.map(() => -1e9), offAt: LAMPS.map(() => 1e12), lv: LAMPS.map(() => 1), flash: 0, bits: [] as Bit[], touched: -1e9, live: true };
    const paint = () => {
      bl.style.transform = `rotate(${s.a.toFixed(4)}rad)`;
      el.style.setProperty("--a", (s.a / A_OPEN).toFixed(3));
      let sum = 0;
      s.lv.forEach((v, i) => { el.style.setProperty(`--l${i}`, v.toFixed(3)); sum += v; });
      el.style.setProperty("--lit", (sum / LAMPS.length).toFixed(3));
      el.style.setProperty("--flash", s.flash.toFixed(3));
    };
    const tell = () => { const now = s.to === 0; if (now !== s.live) { s.live = now; setLive(now); } };
    const arc = (n: number, power: number) => {
      if (reduce) return;
      s.flash = Math.max(s.flash, power);
      for (let i = 0; i < n; i++) {
        const dir = -Math.PI / 2 + (Math.random() - 0.5) * 2.6, v = (120 + Math.random() * 380) * power, max = 0.22 + Math.random() * 0.42;
        s.bits.push({ x: 130 + (Math.random() - 0.5) * 8, y: 126, vx: Math.cos(dir) * v, vy: Math.sin(dir) * v, life: max, max });
      }
    };
    const drawBits = (dt: number) => {
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      ctx.clearRect(0, 0, 260, 260);
      if (s.flash > 0.01) {
        const g = ctx.createRadialGradient(130, 126, 0, 130, 126, 70 * s.flash + 20);
        g.addColorStop(0, `rgba(255,255,255,${0.95 * s.flash})`); g.addColorStop(0.25, `rgba(170,210,255,${0.6 * s.flash})`); g.addColorStop(1, "rgba(79,152,251,0)");
        ctx.fillStyle = g; ctx.fillRect(0, 0, 260, 260);
      }
      ctx.globalCompositeOperation = "lighter"; ctx.lineCap = "round"; ctx.shadowColor = "rgba(79,152,251,0.9)"; ctx.shadowBlur = 7 * dpr;
      for (const b of s.bits) {
        const ox = b.x, oy = b.y;
        b.vy += 900 * dt; b.vx *= 1 - 2.2 * dt; b.x += b.vx * dt; b.y += b.vy * dt; b.life -= dt;
        const k = Math.max(0, b.life / b.max);
        ctx.strokeStyle = `rgba(${170 + 85 * k},${210 + 45 * k},255,${Math.min(1, k * 1.6)})`; ctx.lineWidth = 1 + 2.2 * k;
        ctx.beginPath(); ctx.moveTo(ox - b.vx * dt * 2.2, oy - b.vy * dt * 2.2); ctx.lineTo(b.x, b.y); ctx.stroke();
        ctx.fillStyle = `rgba(255,255,255,${k})`; ctx.beginPath(); ctx.arc(b.x, b.y, 1.1 + k, 0, 6.3); ctx.fill();
      }
      ctx.globalCompositeOperation = "source-over"; ctx.shadowBlur = 0;
      s.bits = s.bits.filter((b) => b.life > 0 && b.y < 172);
    };

    let raf = 0, last = 0, seen = true, timer = 0, begin = () => {};
    const frame = (now: number) => {
      raf = 0;
      const dt = Math.max(0.004, Math.min(0.032, (now - last) / 1000 || 0.016)); last = now;
      const before = s.a;
      if (!s.drag) {
        // thrown down by hand weight, gripped by the jaw for the last few degrees, sprung up when pulled
        const inJaw = s.a < 0.12;
        const pull = s.to === 0 ? -20 - 16 * s.a : 30 * (A_OPEN + 0.06 - s.a) + 4;
        s.w += (pull - (inJaw ? 13 : 3.6) * s.w) * dt; s.a += s.w * dt;
        if (s.a < 0) { s.a = 0; s.w = s.w < -1.6 ? -s.w * 0.1 : 0; }
        if (s.a > A_OPEN) { s.a = A_OPEN; s.w = s.w > 0.5 ? -s.w * 0.3 : 0; }
      }
      // the arc jumps just before the blade lands, and a smaller one as it leaves
      if (before > 0.1 && s.a <= 0.1 && s.a < before) arc(38, 1);
      const made = s.a < 0.06;
      if (made && !s.made) { s.onAt = LAMPS.map((_, i) => now + 70 + i * 140); s.offAt = LAMPS.map(() => 1e12); }
      if (!made && s.made) { arc(12, 0.55); s.offAt = LAMPS.map((_, i) => now + i * 45); s.onAt = LAMPS.map(() => 1e12); }
      s.made = made;
      let busy = false;
      s.lv = s.lv.map((v, i) => {
        const t = now - s.onAt[i];
        if (now >= s.offAt[i]) { const n = v * Math.exp(-dt / 0.14); if (n > 0.004) busy = true; return n > 0.004 ? n : 0; }
        if (t < 0) { if (s.onAt[i] < 1e11) busy = true; return v; }
        if (t < 520) busy = true;
        return t < 55 ? 0.6 : t < 115 ? 0.12 : t < 180 ? 0.85 : t < 250 ? 0.45 : t < 520 ? 0.8 + 0.2 * ((t - 250) / 270) : 1;
      });
      s.flash *= Math.exp(-dt / 0.09); if (s.flash < 0.01) s.flash = 0;
      paint(); drawBits(dt);
      const rest = !s.drag && !busy && s.flash === 0 && s.bits.length === 0 && Math.abs(s.w) < 0.003 && (s.a === 0 || s.a === A_OPEN);
      if (rest) return;
      if (seen && !document.hidden) raf = requestAnimationFrame(frame);
    };
    const wake = () => { if (!raf) { last = performance.now(); raf = requestAnimationFrame(frame); } };
    const go = (closed: boolean) => {
      s.to = closed ? 0 : A_OPEN; tell();
      if (reduce) { s.a = s.to; s.w = 0; s.made = closed; s.lv = LAMPS.map(() => (closed ? 1 : 0)); s.onAt = LAMPS.map(() => -1e9); s.offAt = LAMPS.map(() => (closed ? 1e12 : -1e9)); paint(); return; }
      s.w += closed ? -1.2 : 2.6; wake();
    };
    api.current = { set: (closed) => { s.touched = performance.now(); go(closed); } };

    // take hold of the grip and throw the switch yourself
    const angle = (e: PointerEvent) => {
      const r = el.getBoundingClientRect(), k = r.width / W;
      return Math.max(0, Math.min(A_OPEN, Math.atan2(r.top + PY * k - e.clientY, r.left + PX * k - e.clientX)));
    };
    let lastA = 0, lastT = 0;
    const down = (e: PointerEvent) => { if (reduce) return; s.drag = true; s.touched = performance.now(); lastA = s.a; lastT = performance.now(); gr.setPointerCapture(e.pointerId); wake(); };
    const move = (e: PointerEvent) => {
      if (!s.drag) return;
      const now = performance.now(), next = angle(e);
      s.w = ((next - lastA) / Math.max(0.008, (now - lastT) / 1000)) * 0.6; s.a = next; lastA = next; lastT = now;
    };
    const up = () => {
      if (!s.drag) return;
      s.drag = false; s.touched = performance.now(); s.w = Math.max(-6, Math.min(6, s.w));
      s.to = s.w < -1 || (s.w < 1 && s.a < A_OPEN * 0.45) ? 0 : A_OPEN; tell(); wake();
    };
    gr.addEventListener("pointerdown", down);
    gr.addEventListener("pointermove", move);
    window.addEventListener("pointerup", up);
    window.addEventListener("pointercancel", up);

    paint();
    // while the circuit is made and nothing else is moving, the lamps breathe very slightly
    const hum = window.setInterval(() => {
      if (reduce || raf || !seen || document.hidden || !s.made || s.a !== 0) return;
      const t = performance.now() / 1000;
      LAMPS.forEach((_, i) => el.style.setProperty(`--l${i}`, (0.94 + 0.06 * Math.sin(t * 2.3 + i * 1.7)).toFixed(3)));
    }, 110);
    if (!reduce) {
      // The demo: lit, open, close with a spark, hold. It stands down while someone is using the switch.
      const loop = (wait: number, closed: boolean) => { timer = window.setTimeout(() => { if (seen && !document.hidden && performance.now() - s.touched > 9000) go(closed); loop(closed ? HOLD : OPEN_FOR, !closed); }, wait); };
      begin = () => loop(FIRST, false);
      if (document.readyState === "complete") begin(); else window.addEventListener("load", begin, { once: true });
    }
    const io = new IntersectionObserver(([entry]) => { seen = entry.isIntersecting; if (seen && (s.a !== s.to || s.drag)) wake(); });
    io.observe(st);
    const vis = () => { if (!document.hidden && s.a !== s.to) wake(); };
    document.addEventListener("visibilitychange", vis);
    return () => {
      cancelAnimationFrame(raf); window.clearTimeout(timer); window.clearInterval(hum); window.removeEventListener("load", begin); api.current = null;
      ro.disconnect(); io.disconnect(); document.removeEventListener("visibilitychange", vis);
      gr.removeEventListener("pointerdown", down); gr.removeEventListener("pointermove", move);
      window.removeEventListener("pointerup", up); window.removeEventListener("pointercancel", up);
    };
  }, []);

  const wire = `M ${PX + 40} ${FEET - 5} C ${PX + 62} ${FEET + 4} ${LAMP_X[0] - 50} ${FEET + 5} ${LAMP_X[0] - 23} ${FEET - 6} ${LAMP_X.slice(1).map((x, i) => `M ${LAMP_X[i] + 23} ${FEET - 6} C ${LAMP_X[i] + 38} ${FEET + 6} ${x - 38} ${FEET + 6} ${x - 23} ${FEET - 6}`).join(" ")} M ${JX - 40} ${FEET - 5} C ${JX - 62} ${FEET - 2} ${JX - 78} ${FEET + 4} ${JX - 84} ${FACE + 2} C ${JX - 88} ${FACE + 20} ${JX - 86} ${BOT - 8} ${JX - 92} ${BOT + 6}`;

  return (
    <div
      className="relative flex min-h-[540px] w-full flex-col items-center justify-center overflow-hidden overflow-clip bg-[#0B0D12] bg-[radial-gradient(80%_60%_at_50%_40%,#161A23_0%,#0B0D12_60%,#06070A_100%)] px-2 py-8 text-[#F6F4EF] sm:min-h-[760px]"
      style={{ fontFamily: FONT }}
    >
      <style>{`
        .brass-knife-switch-root { --a: 0; --lit: 1; --flash: 0; --l0: 1; --l1: 1; --l2: 1; --l3: 1; }
        @media (prefers-reduced-motion: reduce) { .brass-knife-switch-root * { transition: none !important; } }
      `}</style>
      <div ref={stage} className="relative flex w-full max-w-[1000px] justify-center" style={{ height: H * zoom }}>
        <div ref={root} className="brass-knife-switch-root relative shrink-0" style={{ width: W, height: H, zoom }}>
          {/* light the lamps throw up the wall, and the cold flash of the arc */}
          <div aria-hidden="true" className="pointer-events-none absolute" style={{ left: 196, top: -20, width: 800, height: 620, background: "radial-gradient(closest-side,rgba(79,152,251,0.34),rgba(79,152,251,0.1) 55%,rgba(79,152,251,0))", opacity: "var(--lit)" }} />
          <div aria-hidden="true" className="pointer-events-none absolute" style={{ left: JX - 300, top: PY - 300, width: 600, height: 600, background: "radial-gradient(closest-side,rgba(190,220,255,0.3),rgba(79,152,251,0))", opacity: "var(--flash)" }} />
          {/* what the lit globes leave on the dark table in front */}
          <div aria-hidden="true" className="pointer-events-none absolute" style={{ left: LAMP_X[0] - 120, top: BOT + 4, width: LAMP_X[3] - LAMP_X[0] + 240, height: 60, background: "radial-gradient(closest-side,rgba(79,152,251,0.3),rgba(79,152,251,0))", opacity: "var(--lit)" }} />
          <div aria-hidden="true" className="absolute" style={{ left: SX - 30, top: BOT - 6, width: SW + 60, height: 34, background: "radial-gradient(closest-side,rgba(0,0,0,0.9),rgba(0,0,0,0))" }} />

          {/* the slate: riven top, sawn front edge with a chamfer */}
          <div aria-hidden="true" className="absolute overflow-hidden" style={{ left: SX, top: TOP, width: SW, height: BOT - TOP, borderRadius: "5px 5px 4px 4px", background: "#1b1e24", boxShadow: "0 0 0 0.5px #000" }}>
            <div className="absolute inset-x-0 top-0" style={{ height: FACE - TOP, background: "linear-gradient(180deg,#23272e 0%,#31363f 55%,#414752 100%)" }} />
            <div className="absolute inset-x-0" style={{ top: FACE - TOP, bottom: 0, background: "linear-gradient(180deg,#2a2e36 0%,#1f2228 18%,#17191e 70%,#0c0d10 100%)" }} />
            <svg className="absolute inset-0 h-full w-full opacity-[0.42] mix-blend-overlay" preserveAspectRatio="none">
              <filter id="brass-knife-switch-slate" x="0" y="0" width="100%" height="100%">
                <feTurbulence type="fractalNoise" baseFrequency="0.018 0.12" numOctaves="5" seed="11" />
                <feDiffuseLighting surfaceScale="1.8" diffuseConstant="1.15" lightingColor="#c8d2e6"><feDistantLight azimuth="260" elevation="48" /></feDiffuseLighting>
              </filter>
              <rect width="100%" height="100%" filter="url(#brass-knife-switch-slate)" />
            </svg>
            <div className="absolute inset-x-0" style={{ top: FACE - TOP - 1, height: 3, background: "linear-gradient(180deg,rgba(255,255,255,0.34),rgba(255,255,255,0.08))" }} />
            {/* pools of lamplight on the stone */}
            {LAMP_X.map((x, i) => <div key={x} className="absolute" style={{ left: x - SX - 70, top: 0, width: 140, height: BOT - TOP, background: "radial-gradient(70px 26px at 50% 15px,rgba(214,232,255,0.7),rgba(79,152,251,0.28) 55%,rgba(79,152,251,0)),radial-gradient(66px 44px at 50% 30px,rgba(79,152,251,0.2),rgba(79,152,251,0))", opacity: `var(--l${i})` }} />)}
            {/* engraved maker's plate */}
            <div className="absolute flex items-center justify-center rounded-[2px]" style={{ left: 262, top: FACE - TOP + 12, width: 216, height: 22, background: "linear-gradient(180deg,#e9cd82 0%,#c29a3e 40%,#9a7424 100%)", boxShadow: "inset 0 1px 0 rgba(255,250,220,0.7), inset 0 -1px 0 rgba(50,32,4,0.6), 0 1px 2px rgba(0,0,0,0.7)" }}>
              <Screw left={5} top={7.5} size={7} /><Screw left={204} top={7.5} size={7} />
              <span className="text-[9.5px] font-extrabold uppercase tracking-[0.14em] text-[#3a2806]" style={{ textShadow: "0 1px 0 rgba(255,244,200,0.7)" }}>{site.address}</span>
            </div>
          </div>

          {/* shadow of the blade on the stone */}
          <div aria-hidden="true" className="absolute" style={{ left: JX - 70, top: FEET - 5, width: BL + 80, height: 12, background: "radial-gradient(closest-side,rgba(0,0,0,0.65),rgba(0,0,0,0))", opacity: "calc(1 - var(--a) * 0.75)", transform: "scaleX(calc(1 - var(--a) * 0.45))", transformOrigin: "100% 50%" }} />

          {/* cloth-covered wire from the switch along the row of holders */}
          <svg aria-hidden="true" className="absolute left-0 top-0" width={W} height={H} style={{ overflow: "visible" }}>
            <path d={wire} fill="none" stroke="rgba(0,0,0,0.55)" strokeWidth="6" strokeLinecap="round" transform="translate(1.5,3)" />
            <path d={wire} fill="none" stroke="#1d4da6" strokeWidth="5.6" strokeLinecap="round" />
            <path d={wire} fill="none" stroke={BLUE} strokeWidth="3.6" strokeLinecap="round" />
            <path d={wire} fill="none" stroke="rgba(255,255,255,0.4)" strokeWidth="1.2" strokeDasharray="1.6 3.2" transform="translate(0,-1)" />
          </svg>

          {/* back leaves of the hinge and the jaw */}
          {[PX, JX].map((x, i) => (
            <div key={x} aria-hidden="true" className="absolute" style={{ left: x - (i ? 9 : 11), top: PY - (i ? 21 : 15), width: i ? 22 : 26, height: FEET - PY + (i ? 20 : 14), borderRadius: i ? "3px 9px 0 0" : "12px 12px 0 0", background: BRASS_X, filter: "brightness(0.62)" }} />
          ))}

          {/* the blade and its grip, turning on the hinge pin */}
          <div ref={blade} className="absolute" style={{ left: PX, top: PY, width: 0, height: 0, willChange: "transform" }}>
            <div aria-hidden="true" className="absolute" style={{ left: -(BL + 26), top: -6, width: BL + 36, height: 12, borderRadius: "2px 6px 6px 2px", background: BRASS, boxShadow: "0 0 0 0.5px #2e2006, inset 0 1px 0 rgba(255,252,230,0.9)" }}>
              <div className="absolute inset-x-[10px] top-[4px] h-[1px] bg-[rgba(60,40,6,0.28)]" />
            </div>
            <div aria-hidden="true" className="absolute" style={{ left: -(BL + 38), top: -10, width: 16, height: 20, borderRadius: 3, background: BRASS, boxShadow: "0 0 0 0.5px #2e2006, inset 0 1px 0 rgba(255,252,230,0.9)" }}>
              <div className="absolute inset-y-0 left-[4px] w-[1px] bg-[rgba(60,40,6,0.45)]" /><div className="absolute inset-y-0 right-[4px] w-[1px] bg-[rgba(60,40,6,0.45)]" />
            </div>
            <div ref={grip} className="absolute touch-none select-none" style={{ left: -(BL + 128), top: -22, width: 104, height: 44, cursor: "grab" }}>
              {/* turned ebonite grip */}
              <div aria-hidden="true" className="absolute" style={{ left: 8, top: 7, width: 84, height: 30, borderRadius: "15px 9px 9px 15px / 15px 12px 12px 15px", background: "linear-gradient(180deg,#7b8190 0%,#3a3e48 10%,#16181d 32%,#08090b 62%,#23262d 86%,#050506 100%)", boxShadow: "0 0 0 0.5px #000, inset 0 0 0 0.5px rgba(255,255,255,0.12), 0 8px 10px -4px rgba(0,0,0,0.8)" }}>
                <div className="absolute left-[10px] right-[12px] top-[4px] h-[3px] rounded-full" style={{ background: "linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,0.8) 30%,rgba(255,255,255,0.3) 70%,rgba(255,255,255,0))", filter: "blur(0.6px)" }} />
                {[58, 64, 70].map((x) => <div key={x} className="absolute inset-y-0 w-[2px]" style={{ left: x, background: "linear-gradient(90deg,rgba(0,0,0,0.9),rgba(255,255,255,0.14))" }} />)}
                <div className="absolute inset-x-[8px] bottom-[5px] h-[5px] rounded-full" style={{ background: "linear-gradient(90deg,rgba(79,152,251,0),rgba(79,152,251,0.5),rgba(79,152,251,0))", filter: "blur(2px)", opacity: "var(--lit)" }} />
              </div>
            </div>
          </div>

          {/* front leaves: the blade passes between each pair */}
          <div aria-hidden="true" className="absolute" style={{ left: PX - 13, top: PY - 17, width: 26, height: FEET - PY + 15, borderRadius: "13px 13px 0 0", background: BRASS_X, boxShadow: "0 0 0 0.5px #2e2006, 2px 0 4px rgba(0,0,0,0.5)" }}>
            <span className="absolute left-[5px] top-[9px] h-[16px] w-[16px] rounded-full" style={{ background: "radial-gradient(circle at 36% 30%,#fffbe2,#d2aa4c 42%,#5a3f0d)", boxShadow: "0 1.5px 2px rgba(0,0,0,0.7), 0 0 0 0.5px #2e2006" }} />
          </div>
          <div aria-hidden="true" className="absolute" style={{ left: JX - 11, top: PY - 23, width: 22, height: FEET - PY + 21, borderRadius: "9px 3px 0 0", clipPath: "polygon(0 0,34% 0,50% 9px,66% 0,100% 0,100% 100%,0 100%)", background: BRASS_X, boxShadow: "0 0 0 0.5px #2e2006" }}>
            <div className="absolute inset-x-[4px] top-[20px] h-[14px] rounded-[2px]" style={{ background: "linear-gradient(180deg,rgba(60,40,6,0.4),rgba(255,250,220,0.3))" }} />
          </div>
          {/* feet, fixing screws and knurled terminals */}
          {[PX, JX].map((x, i) => (
            <div key={x} aria-hidden="true" className="absolute" style={{ left: x - (i ? 44 : 22), top: FEET - 6, width: 66, height: 8, borderRadius: 2, background: BRASS, boxShadow: "0 0 0 0.5px #2e2006, 0 3px 4px rgba(0,0,0,0.7)" }}>
              <div className="absolute" style={{ left: i ? 2 : 46, top: -14, width: 18, height: 14, borderRadius: "3px 3px 1px 1px", background: "repeating-linear-gradient(90deg,#fff0bb 0 1px,#b98d30 1px 2.4px,#6b4c12 2.4px 3.4px)", boxShadow: "0 0 0 0.5px #2e2006, inset 0 2px 0 rgba(255,250,220,0.5), inset 0 -3px 3px rgba(40,26,2,0.6)" }} />
              <div className="absolute" style={{ left: i ? 7 : 51, top: -19, width: 8, height: 6, borderRadius: "2px 2px 0 0", background: BRASS_X }} />
            </div>
          ))}
          <canvas ref={sparks} aria-hidden="true" className="pointer-events-none absolute" style={{ left: JX - 130, top: PY - 126, width: 260, height: 260 }} />

          {/* four opal globes in porcelain holders */}
          <div role="img" aria-label={live ? "Four lamps lit, spelling live" : "Four lamps, unlit"}>
            {LAMPS.map((ch, i) => (
              <div key={ch} className="absolute" style={{ left: LAMP_X[i], top: FEET }}>
                <div className="absolute" style={{ left: -34, top: -3, width: 68, height: 10, background: "radial-gradient(closest-side,rgba(0,0,0,0.7),rgba(0,0,0,0))" }} />
                <div className="absolute" style={{ left: -25, top: -24, width: 50, height: 24, borderRadius: "7px 7px 4px 4px / 8px 8px 4px 4px", background: "linear-gradient(90deg,#6d6f76 0%,#c9c8c2 18%,#fbfaf5 38%,#ffffff 46%,#dcdad2 66%,#9a9b9f 88%,#55575e 100%)", boxShadow: "inset 0 -5px 6px rgba(20,24,40,0.35), inset 0 2px 1px rgba(255,255,255,0.9), 0 0 0 0.5px #000", filter: `brightness(calc(0.5 + 0.5 * var(--l${i})))` }}>
                  <div className="absolute inset-x-0 top-[9px] h-[1.5px] bg-[rgba(20,24,40,0.22)]" />
                </div>
                <div className="absolute" style={{ left: -16, top: -37, width: 32, height: 14, borderRadius: "3px 3px 1px 1px", background: "repeating-linear-gradient(180deg,rgba(60,40,6,0) 0 3px,rgba(60,40,6,0.45) 3px 4px),linear-gradient(90deg,#4f370a 0%,#a67a22 16%,#f1d587 36%,#fff4c8 44%,#d2a846 58%,#8c661a 82%,#402c07 100%)", boxShadow: "0 0 0 0.5px #2e2006" }} />
                <div className="absolute rounded-full" style={{ left: -32, top: -98, width: 64, height: 64, background: "radial-gradient(circle at 34% 27%,#dfe3ea 0%,#b4bac6 16%,#878e9c 44%,#5c6372 72%,#353b48 100%)", boxShadow: "0 0 0 0.5px #000, inset -6px -8px 12px rgba(10,12,20,0.5)" }}>
                  <div className="absolute inset-0 rounded-full" style={{ background: "radial-gradient(circle at 50% 56%,#ffffff 0%,#f4f9ff 34%,#c4deff 62%,#7db4ff 86%,#4F98FB 100%)", boxShadow: "0 0 18px 4px rgba(79,152,251,0.85), 0 0 60px 18px rgba(79,152,251,0.42), 0 0 130px 46px rgba(79,152,251,0.2)", opacity: `var(--l${i})` }} />
                  <div className="absolute inset-0 flex items-center justify-center text-[31px] font-black leading-none tracking-[-0.02em] text-[#0B0D12]" style={{ opacity: 0.9 }}>{ch}</div>
                  <div className="absolute left-[11px] top-[7px] h-[14px] w-[22px] rounded-full" style={{ background: "radial-gradient(closest-side,rgba(255,255,255,0.85),rgba(255,255,255,0))", transform: "rotate(-32deg)" }} />
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>

      <div className="relative mt-2 flex items-center gap-[12px]">
        <span className="flex h-[30px] items-center gap-[8px] rounded-full bg-[#F6F4EF]/[0.08] pl-[10px] pr-[13px] text-[11px] font-extrabold uppercase tracking-[0.18em] text-[#F6F4EF]">
          <span aria-hidden="true" className="h-[9px] w-[9px] rounded-full" style={{ background: live ? BLUE : "#5b6170", boxShadow: live ? "0 0 0 4px rgba(79,152,251,0.25)" : "none" }} />
          {live ? "Live" : "Draft"}
        </span>
        <button
          type="button"
          role="switch"
          aria-checked={live}
          onClick={() => api.current?.set(!live)}
          className="flex h-[52px] items-center rounded-full bg-[#F6F4EF] px-[26px] text-[15px] font-extrabold tracking-[-0.01em] text-[#0B0D12] shadow-[inset_0_-3px_0_rgba(11,13,18,0.14),0_18px_30px_-14px_rgba(0,0,0,0.9)] outline-none transition-transform duration-150 active:scale-[0.96] focus-visible:ring-2 focus-visible:ring-[#4F98FB] focus-visible:ring-offset-2 focus-visible:ring-offset-[#0B0D12] motion-reduce:transition-none"
        >
          {live ? "Open the switch" : "Throw the switch"}
        </button>
      </div>
      <p aria-live="polite" className="mt-[12px] text-center text-[12px] font-semibold tracking-[-0.005em] text-[#F6F4EF]/75">
        {live ? `${site.name} is live: blade home, all four lamps lit` : "Draft: blade up, circuit open, lamps dark"}
      </p>
    </div>
  );
}

Install with one command: npx shadcn@latest add https://we.inc/r/brass-knife-switch-on-a-slate-base-that-closes-with-a-spark-and-lights-four-opal-lamps-spelling-live.json

When to use it

How to customize it

Accessibility

Questions

How do the lamps light the things around them?

The loop writes one custom property per lamp, from 0 to 1, plus their average. The glow on each globe, the pool on the slate under it, the brightness of its porcelain holder, the wash on the wall and the rim light on the grip all take their opacity from those numbers.

Why does the blade slow down just before it lands?

Inside the last `0.12` radians the drag on the blade is more than three times higher, which stands in for the spring leaves of the jaw pinching it. It also means pulling it out starts slowly and then lets go.

Can I drag it on a touch screen?

Yes. The grip has `touch-action: none` and captures the pointer, and the angle is measured from the hinge pin to your finger. Let go below roughly half way and it closes; a quick flick wins over position.

How do I connect it to a real publish action?

Run your request in the button's `onClick`, then call `api.current?.set(true)` to close the switch when it succeeds or `set(false)` to open it. `live` holds the side the blade is heading for.

Is the stone a photograph?

No. It is an SVG `feTurbulence` stretched sideways and lit with `feDiffuseLighting`, laid over two flat gradients for the top and the sawn front edge. Change `seed` for a different slab.

Related: Steel Roller Shutter Stencilled Draft That Rattles Up to Show a Lit Shop Window Holding the Live Site, Brass Dolly Light Switch Toggle on a Fluted Rose That Snaps Over and Lights a Filament Wall Lamp, Satin Opening Ribbon on Brass Posts That Brass Scissors Cut So Both Halves Flutter Down and the Page Goes Live.

More we.inc originals or all free UI components. Start for free to have a full site built around it.

More in Originals

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap