npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@siltrun/wire

v0.1.2

Published

Silt binary wire codec: a declarative field-type combinator that encodes and decodes from one schema on both sides, for the wire:"binary" tier. Zero-dep, realm-safe.

Downloads

51

Readme

@siltrun/wire

Binary encoding for Silt room state. Declare the field types of your state once and the same declaration gives you both encode(state) -> Uint8Array and decode(bytes) -> state. The server encodes with it and the browser decodes with it, from one shared module, so the two sides cannot drift apart.

Zero dependencies. It uses only DataView, TextEncoder, and Uint8Array, and it runs outside tick(), so it never touches room determinism.

This package also holds the delta codec behind a room's wire: "delta" tier.

Install

npm i @siltrun/wire

Declare a schema

// schema.ts, imported by the room and by the client
import { schema, struct, array, str, u8, varint } from "@siltrun/wire";

export type State = { tick: number; ships: { id: string; x: number; y: number }[] };

export const gameWire = schema(
  struct({
    tick: varint,
    ships: array(struct({ id: str, x: u8, y: u8 })),
  }),
);
const bytes = gameWire.encode({ tick: 42, ships: [{ id: "a1", x: 10, y: 200 }] });
gameWire.decode(bytes); // back to the same object

That state is 48 bytes as JSON and 7 bytes here.

Wire it into a room

The room declares the schema, and the client passes the same object to joinRoom:

// room.ts
import type { Room } from "@siltrun/room";
import { gameWire, type State } from "./schema.ts";

export default {
  wire: { encoding: "binary", schema: gameWire },
  tick(state = { tick: 0, ships: [] }, inputs) { /* ... */ return state; },
} satisfies Room<State>;
// the client
import { joinRoom } from "@siltrun/client";
import { gameWire } from "./schema.ts";

const room = await joinRoom(url, { id, wire: gameWire });

Only decode is used browser-side. If a room negotiates binary and the client supplies no codec, per-tick state datagrams throw rather than silently arriving as garbage.

Field types

| Combinator | Encodes | |---|---| | u8, u16, i16 | fixed-width integers | | varint | unsigned LEB128, so small numbers cost one byte | | zigzag | signed integers, compact near zero | | bool | one byte | | str | length-prefixed UTF-8 | | array(el) | length-prefixed homogeneous list | | nullable(el) | a value or null, one tag byte | | struct(fields) | a fixed set of named fields | | enumOf(values) | a string enum as a single tag byte | | rle(el) | run-length-encoded flat number array, for grids and tile maps |

Declaration order inside a struct is the wire order. Both sides read the same declaration, so that order stays in sync by construction.

Writer, Reader, and the Codec<T> type are exported too, for the cases where a field wants packing the combinators do not cover. A hand-written codec is an object with w(writer, value) and r(reader), and it composes with the rest.

A schema does not have to be lossless. Anything you leave out of the codec simply does not ride the per-tick snapshot, which is a normal way to keep server-only state server-side and send flavor over the reliable lane instead.

Delta

diffState, applyDelta, encodeDelta, and decodeDelta implement the platform-generic delta tier. A room opts in with wire: "delta" and returns its natural state; the platform diffs consecutive states and sends the difference. That path needs no authoring, so most rooms never call these directly.

Docs

Full guides and API reference: https://silt.run/docs/