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

@caputchin/preset-phaser

v0.2.0

Published

Run a FULL headless Phaser 4 game (Arcade physics included) as a Caputchin deterministic-replay sim. The engine itself is the server run: the @caputchin/determinism kit makes it deterministic (transcendental Math swap + headless DOM boot), plus a seeded R

Readme

@caputchin/preset-phaser

Run a headless Phaser 4 game as a Caputchin deterministic-replay sim. Phaser itself is the server run (the engine is the sim, not a hand-rolled stand-in): the same scene logic renders in the player's browser and re-executes on the server isolate over the recorded trace.

This preset depends on no shared replay kit. Phaser boots headless via its own headlessStep, gameplay randomness comes from Phaser.Math.RandomDataGenerator seeded from the platform seed, and a small boot shim supplies the deterministic stubs Phaser needs inside the sealed isolate (no DOM, frozen clock, codegen disabled).

Install

pnpm add @caputchin/preset-phaser @caputchin/game-sdk phaser

phaser is a peer dependency: you pin the Phaser version your game targets (^4.1).

The one rule: import the shim first in your run entry

Phaser reads window and Image while its module evaluates, not only at new Phaser.Game(...). So the headless shim must be installed before phaser is imported. In your replay entry, make @caputchin/preset-phaser/install the first import, before anything that pulls phaser:

// src/run.ts (the headless replay entry)
import '@caputchin/preset-phaser/install'; // MUST be first
import { makePhaserRun } from '@caputchin/preset-phaser';
import { gameSim, decode } from './sim.js'; // imports phaser

export const run = makePhaserRun({
  width: 640,
  height: 400,
  maxTicks: 60 * 60, // hard ceiling (~60s at 60Hz)
  decode,
  sim: gameSim, // ({ seed, config, currentTick, currentAction, rng }) => hooks
});

makePhaserRun returns a conforming run(seed, config, trace) => Verdict. Do not import /install in your live (browser) build: the real DOM is present there.

Sharing one scene across live and replay

Write the sim hooks (create / update / result / optional isOver) once and use them in both entries. The live entry records the player's per-tick action into the trace and renders with Phaser as usual; the replay entry feeds the recorded actions back through the same hooks. Seed all gameplay randomness with seedFromPlatform(seed) so both sides draw the identical sequence.

// src/index.ts (the live entry)
import { register } from '@caputchin/game-sdk';
import { seedFromPlatform } from '@caputchin/preset-phaser';
// ... live Phaser game, render + input capture, bridge.pass({ trace }) on win

Build

// tsup.config.ts
import { defineConfig } from 'tsup';
import { definePhaserBuild } from '@caputchin/preset-phaser/build';

export default defineConfig(definePhaserBuild({ gameId: 'my-game' }));

This emits a minified IIFE live bundle (dist/my-game.js, phaser and assets inlined for the iframe CSP) and a minified ESM headless bundle (dist/run.js) for the replay isolate.

Determinism

The sim must be reproducible bit-for-bit across the browser and the server isolate. Keep gameplay math integer or fixed-point, avoid native trig (Math.sin and friends diverge across CPUs; reflect by flipping velocity components instead), and take all randomness from seedFromPlatform. The shim freezes the clock and seeds Phaser's internal Math.random, matching the isolate. Verify before publish with caputchin-selfcheck dist/run.js.

API

| Export | Purpose | |---|---| | @caputchin/preset-phaser/install | side-effect import that installs the headless shim at module load | | makePhaserRun(opts) | build the conforming run from your sim hooks | | seedFromPlatform(seed) | a Phaser.Math.RandomDataGenerator seeded from the platform seed | | bootHeadlessPhaser(config) | boot a Phaser.HEADLESS game and resolve when ready (advanced) | | applyPhaserShim(seed?) | install the shim manually (advanced) | | @caputchin/preset-phaser/build definePhaserBuild(opts) | the dual live + headless tsup config |