Skip to main content
Back to articles
2026 / 01
| 2 min read

Build System Groundwork and Modem Plumbing

Making the WASM build honest about its dependencies, loading backends on dial, and giving the modem one source of truth for pacing.

emulator build-system modem wasm vite

I wasted an hour debugging a modem timing issue that did not exist. The bug was in yesterday’s code, because I was running a stale WASM build. A build system that isn’t honest about its dependencies turns debugging into archaeology.

So I stopped and fixed the pipeline. The modem-core WASM build is now a first-class step in the Makefile, the Vite entry no longer assumes imports are fresh, and production builds go through the same path as development. The constraint is simple: if the frontend runs, it runs today’s code.

With the build predictable, I moved the modem toward a single source of truth for pacing. A modem is a state machine with explicit delays and buffer limits, not a socket wearing a baud rate. The byte interval now derives from the profile rather than from constants scattered through the transmit path:

At this point in the work, the profile still used a three-second handshake window:

export const Bell103: ModemProfile = {
  baudRate: 300,
  audio: {
    originateCarrierHz: 1170,
    answerCarrierHz: 2125,
    markHz: 1270,
    spaceHz: 1070,
  },
  dialSequence: {
    dialToneMs: 250,
    dtmfToneMs: 80,
    dtmfGapMs: 70,
    postDialSilenceMs: 700,
    handshakeMs: 3000,
  },
  flowControl: 'RTS/CTS',
};

Those numbers give the dial tone and handshake a predictable shape, and backends no longer have to care: the modem owns the transport clock.

I also moved backend loading to the dial path. If you never call a service, it never ships to the browser, and the initial payload dropped by about 30 KB. The interaction changes from “choose a mode” to “dial a system,” which is the mental model I wanted in the first place.

Tomorrow: the big repo restructure. The build is honest now, so I can move files without wondering whether I am testing the version I just edited.

This set the stage for the big repo restructure. Previous: 2026-01-21