SYS UNDER THE HOOD / NERD OUTSMALL BY DESIGN

Small games.
Serious engineering.

A webpage is a surprisingly good game map. The trick is reading it cheaply, changing only what you own, and leaving cleanly. Everything below runs on one tiny engine loop, the same way the games do. Poke it. Scroll away and it sleeps.

00 INSERT COIN

Two Macs, one network, and Bolo.

Middle school engineering tech class: a room of networked Macs and a tank game called Bolo. The gameplay was good for its day. The networking is what hooked me.

We weren’t always supposed to be playing, but we could reach across the network and change what was happening on someone else’s screen. Once that clicked, I wanted to know how all of it worked, and the way to find out was to build things: apps, websites, games, anything that could talk to something else.

DOM VIRUS is the same trick, pointed at a webpage: a game that reaches into the page you’re reading.

Coming soon: DOM Battlefield multiplayer. Two players, two pages, one battle.

MAC 01 · YOU00
MAC 02 · THEM00
01 THE PAGE BECOMES THE BOARD

One host. Two worlds.

A custom host attaches a Shadow Root for the canvas and controls, so game UI styles never leak into your page. The board adapter reads real DOM geometry once, caches it, and the simulation plays against that map. Letters and buttons stay in the real document.

Turn on X-ray to see what the game sees. The bug walks around real elements. Click the button: buttons are enemy factories.

your.page

Hello, world.

Paragraphs become terrain.

Text is cover.

BUGS 1 / 6
02 A FRAME, NOT A FREE-FOR-ALL

One loop. Bounded work.

One requestAnimationFrame loop. A spatial grid narrows collisions. Bullets, enemies and particles live in fixed pools with hard ceilings, so a long session never grows its memory. Projectiles query cached geometry instead of asking the browser for layout every shot.

Spawn as much as you like. The pool holds 32: past that the engine says no, and the frame stays inside its budget.

FRAME16.7ms
ACTIVE 00 / 32 · REJECTED 0 · ALLOCATIONS 0
03 THE PART WE CARE ABOUT MOST

Recall gives the page back.

Hits rewrite characters inside the existing Text node to a literal 0 or 1. No clones, no per-letter wrappers. An ownership ledger records the original and what the game wrote. Recall restores only what is still the game’s; if your app changed it since, your app wins.

Fire at the sentence, let “your app” edit a hit letter, then Recall.

Hello, world. Same page, different rules.

    OWNED 0
    04 SPEC SHEET

    Hard limits, in actual numbers.

    Limits constrain work; they are not frame-rate promises. Real frame time still depends on the page, fonts and device.

    • 1rAF loopOne frame loop drives the whole game.
    • 100particle slotsReused, never re-allocated.
    • 8,000glyphs indexed900 Range reads per refresh, max.
    • 32page targets160 text containers, chosen by selector.
    • 12.5 Hzdirty geometry2 Hz once the page is stable.
    • 10 HzHUD updatesSeparate from the canvas.
    • 1.5×canvas DPR capSharp enough, never wasteful.
    • 24score popupsPooled, like everything else.
    • Sherman Bytes27.0 kB gzip
    • Swarm Protocol34.6 kB gzip
    • Byte Runner29.2 kB gzip
    • Null Invaders22.9 kB gzip

    Sizes are measured at site build from each package’s distribution files (gzip, decimal kB). Null Invaders caps aliens at 48 and bullets at 80; Byte Runner caps flies at 12; Sherman Bytes caps tanks at 32 and shells at 120; Swarm caps bugs at 48.

    05 INDEPENDENT PACKAGES · SHARED FOUNDATIONS

    Build once. Ship each.

    The engine lives here. Each game gets a fingerprinted snapshot, tests itself and tags its own release. The hub pins exact versions and Pages serves static files: no runtime iframe, no remote content service, no client framework.

    1. src/engine
    2. sync:gamessnapshot + ORIGIN.json
    3. game repotest · tag vX
    4. games.jsonhub pin
    5. Pagesstatic, no server
    READY
    DEV BRING YOUR OWN PLAYGROUNDMIT LICENSED

    Your page is next.

    Import a game, choose the targets, and start a session. The launcher is optional. React adapters are separate exports so plain JavaScript consumers do not pay for React.

    Sherman Bytes

    Shared TypeScript runtime · original single-player tank simulation

    sherman-bytes.jsJS / ESM
    import { createShermanBytes } from "@coded-design/sherman-bytes";
    
    const game = createShermanBytes({
      root: "main",
      textSelector: "h1, h2, p",
      targetSelector: "button, [data-base]",
      wallSelector: "[data-sherman-wall]",
      binaryOpacity: 0.32,
      mode: "siege", // or "conquest"
      fortifications: true,
    });
    game.start();
    // Later: game.destroy();
    Choose your elements. Start playing.

    Swarm Protocol

    Established Swarm engine

    swarm-protocol.jsJS / ESM
    import { installSwarm } from "@chriscooley/swarm-protocol";
    
    const swarm = installSwarm({
      textSelector: "[data-swarm-text]",
      targetSelector: "[data-swarm-target]",
      keyboard: false,
      triggerSelector: false,
    });
    await swarm.start();
    // Later: swarm.destroy();
    Choose your elements. Start playing.

    Byte Runner

    Shared TypeScript runtime

    byte-runner.jsJS / ESM
    import { createByteRunner } from "@coded-design/byte-runner";
    
    const game = createByteRunner({
      root: "main",
      textSelector: "h1, h2, p, li",
      targetSelector: "[data-gate]",
      theme: "system",
    });
    game.start();
    // Later: game.destroy();
    Choose your elements. Start playing.

    Null Invaders

    Shared TypeScript runtime

    null-invaders.jsJS / ESM
    import { createNullInvaders } from "@coded-design/null-invaders";
    
    const game = createNullInvaders({
      root: "main",
      textSelector: "h1, h2, p",
      targetSelector: "[data-factory]",
      targetEffects: "liquid",
    });
    game.start();
    // Later: game.destroy();
    Choose your elements. Start playing.

    Package names show the import after installation. Use each repository’s README for its available install or release route; registry publication is separate from this demo. Start with a static content container and exclude application controls you want to preserve.