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

game-engine-core-web

v0.2.0

Published

Browser client SDK for game-engine-core — interactive GameWebClient + passive observer/replay

Readme

game-engine-core-web

Browser client SDK for game-engine-core.

npm: https://www.npmjs.com/package/game-engine-core-web GitHub: https://github.com/stevenlundy/game-engine-core

This package provides two things:

  1. GameWebClient — an interactive abstract base class for writing browser-based AI agents that play live games against the engine.
  2. ReplayPlayer + fetchGlog — a passive observer SDK for replaying finished game sessions in the browser.

Transport strategy: Option A (one long-lived stream)

The GameWebClient opens a single bidirectional Play stream for the entire game. Because the game is turn-based the protocol is naturally sequential:

open stream
  ← recv StateUpdate  (server sends first state)
  if terminal → close, done
  → call onStateUpdate(update)  (subclass decides action)
  → send Action
  ← recv StateUpdate
  ...repeat until terminal...

This avoids the overhead of opening a new HTTP request per turn and keeps the implementation identical to the ts-node client.

Envoy gRPC-Web proxy

Browsers cannot speak raw HTTP/2 gRPC. You need an Envoy proxy in front of the game-engine server to translate gRPC-Web (HTTP/1.1) to gRPC (HTTP/2).

Start one with Docker:

docker run --rm -p 8080:8080 \
  -v "$(pwd)/docker/envoy.yaml:/etc/envoy/envoy.yaml:ro" \
  envoyproxy/envoy:v1.29-latest \
  -c /etc/envoy/envoy.yaml

The configuration in docker/envoy.yaml listens on port 8080 and proxies to host.docker.internal:50051 (where the game-engine gRPC server runs).


Quickstart

1 — Install

npm install game-engine-core-web

Pinning to a specific version:

npm install [email protected]

2 — Subclass GameWebClient

import { GameWebClient } from "game-engine-core-web";
import type { Action, StateUpdate } from "game-engine-core-web";

class MyAgent extends GameWebClient {
  onStateUpdate(update: StateUpdate): Action {
    // Parse the state and decide what to do
    const payload = JSON.parse(Buffer.from(update.state!.payload).toString());
    // ... your logic here ...
    return {
      actorId: "",                              // stamped automatically by run()
      payload: Buffer.from(JSON.stringify({ type: "draw_card" })),
      timestampMs: Date.now(),
    };
  }
}

// Connect through the Envoy proxy on port 8080
const agent = new MyAgent("http://localhost:8080", "player-1");

const sessionId = await agent.joinLobby("crazy-eights");
console.log("session:", sessionId);

await agent.run();
agent.close();

See examples/randomAgent.ts for a complete working example.

3 — Replay viewer

import { fetchGlog, ReplayPlayer } from "game-engine-core-web";

const player = await fetchGlog("https://your-server/sessions/abc123.glog");

player.onEntry = (entry, index) => {
  console.log(`Step ${index}: actor=${entry.actorId} terminal=${entry.isTerminal}`);
};
player.onComplete = () => console.log("Done!");
player.play(500); // 500 ms per step

Migration from ts-node

To swap the ts-node GameClient for the browser GameWebClient:

-import { GameClient } from "game-engine-core-node";
+import { GameWebClient as GameClient } from "game-engine-core-web";

That's it — the public API (constructor, joinLobby, run, onStateUpdate, close) is identical.


API reference

GameWebClient (abstract)

| Member | Description | |--------|-------------| | constructor(serverUrl, playerId) | serverUrl is the Envoy proxy URL (e.g. "http://localhost:8080"). | | joinLobby(gameType): Promise<string> | Join a lobby; resolves with sessionId when the game starts. | | run(): Promise<void> | Open one stream, loop until terminal. | | abstract onStateUpdate(update): Action \| Promise<Action> | Override to implement your agent logic. | | close(): void | Shut down gRPC channels. | | protected createMatchmakingClient() | Override for testing or custom transports. | | protected createGameSessionClient() | Override for testing or custom transports. |

RichState / parseRichState

import { parseRichState } from "game-engine-core-web";

const rich = parseRichState(update);
console.log(rich.gameState);   // parsed JSON payload
console.log(rich.stepIndex);
console.log(rich.isTerminal);

Development

make install      # npm install
make build        # tsc → dist/
make test         # Jest tests
make lint         # Biome lint
make fmt          # Biome format
make type-check   # tsc --noEmit

Regenerating protobuf stubs

npm run proto

Requires protoc in PATH and ts-proto (npm install handles ts-proto).