Switchboard

Patch anything into Pennywire.

Fig. 1 — Switchboard, live captureOpen the live demo ↗10 s loop · recorded frame by frame on GPU

Field notes

An integrations page that is a 1940s telephone switchboard. Drag a cloth cord up into a jack to patch a service in, patch both cords of a circuit to route one service into another, and the card writes the recipe and the code for it.

  • Pointer interaction
  • SaaS
  • Developer tool
  • Dark theme

Switchboard is the integrations page of Pennywire, a fictional developer platform, drawn as a walnut telephone switchboard with twelve brass-plated jacks and four cloth cords on the shelf. Drag a cord up into a jack, or just click the jack, and its amber lamp lights, a dotted current runs along the cord and the card beside the board shows the service, a snippet to copy and its sample traffic. The cords come in two circuits: patch both ends of one and it routes one service into the other, so the card writes the recipe, "When Forkyard sees a push to main, then Murmurlane posts it to #ops", and the route() call for it.

Red lamps are lines calling in; patch one to answer it. Yank a cord out fast and it sparks and whips; throw the CLEAR lever and every cord drops back to the shelf, lamps going out one by one. Every service and string lives in one file, and your own OAuth or API plugs into four functions that hear only what really changed once the board is still. A tiny synth clicks only for your own moves. It is plain DOM and SVG, with no WebGL: keyboard users patch from the jacks, reduced motion opens on a still board, and on a phone the board goes to four columns with the card below.

How it's built

  • The board is plain DOM and SVG, with no WebGL: the jacks are real buttons with real text, and the cabinet, brass and bakelite are CSS gradients. The page measures where every jack and shelf hole sits and hands those points to a pure frame function that places the plugs and draws the cords.
  • A cord is a curve, not a simulation. Its shape comes from its two ends: a sag from a fixed slack, extra slack lying on the shelf, and a sideways swing after each move from a (1 − u)² envelope that ends at exactly zero. So any frame can be drawn on its own, and the preview is recorded frame by frame.
  • The state keeps only what was asked for and when (each move, swing, spark, call and clear), never how far along it is. A move that starts mid-flight starts from where the earlier move had the plug at that moment. The 10-second tour is the same state built from a script, and the live page takes it over on the first touch with no jump.
  • The backend hears from the settled board, not from gestures. Once nothing moves, the page compares what is patched and routed with what it last told the backend and calls connect, disconnect, route and unroute for the difference. So lifting a plug and dropping it back calls nothing, and the tour's cords were never connected. A rejected call undoes just that step and shows its message in red.
  • A Node check proves the copy fits the plates, the cords never dip below the shelf, the picking order, the backend diff, the loop's second 10 equalling second 0, no plug jumping in 1 ms steps, and the hand-over from the tour.

Inside the prompt

Every file below is written out in full, so your agent creates the project exactly — no guessing, no missing pieces.

switchboard-integrations/
├─ .gitignore
├─ check.ts
├─ index.html
├─ package.json
├─ tsconfig.json
├─ vite.config.ts
└─ src/
   ├─ App.tsx
   ├─ index.css
   ├─ main.tsx
   ├─ vite-env.d.ts
   ├─ components/
   │  ├─ Board.tsx
   │  ├─ Card.tsx
   │  └─ Page.tsx
   └─ lib/
      ├─ board.ts
      ├─ copy.ts
      ├─ cord.ts
      ├─ integrations.ts
      ├─ live.ts
      ├─ look.ts
      ├─ loop.ts
      ├─ sound.ts
      └─ time.ts

Recut it

  • Rename the platform, the twelve services and every stringsrc/lib/copy.ts + index.html → SERVICES / COPY / <title>
  • Wire your own OAuth or APIsrc/lib/integrations.ts → connect / disconnect / route / unroute
  • Re-colour the page, the cabinet and the cordssrc/lib/look.ts + src/index.css → COLORS / CORDS / --sb-…
  • Retime the moves, swings and calling linessrc/lib/look.ts → SEAT / RETURN / SWING / CALL
  • Retime the 10-second toursrc/lib/board.ts → tourState
  • Turn the sounds off by defaultsrc/lib/sound.ts → on
  • Check the loop still closes and the copy fitscheck.ts → pnpm check

Also in the vault