ProtoHax UserScript
ProtoHax UserScript lets you write your own ProtoHax client modules in TypeScript. A userscript declares a module — its name, category, and options — and wires up listeners against the live game session: game events, packets, the entity/world model, the local player, inventory, and the raw packet connection.
Modules you author this way sit alongside the built-in ones in the client menu. They can be toggled on and off, expose sliders and toggles and color pickers, and read or drive the game exactly like a first-party module.
The @protohax/userscript package
Everything is typed through a single package on npm:
This package is types-only. It ships a single index.d.ts and no runtime
code. That is deliberate:
- The types describe the authoring API and the host's own game model, so
your editor autocompletes
ctx.session.entityState.localPlayer.jump()and type-checks every packet payload. - The values you import from it —
defineModule,moduleManager, the entity classes,AbstractBlockLocationTracker,nbt,utils— are resolved at runtime to the host's live singletons when your script is bundled into the client. Your script and the client share one instance of the game state, one module manager, and one (patched)prismarine-nbt.
In other words: you install the package for the types, and the ProtoHax client supplies the implementation when your script runs.
Install
npm install --save-dev @protohax/userscript
tsconfig.json
A minimal config that works with the published declarations:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true
}
}
Note —
skipLibCheckis required. The published.d.tsvendors the host's packet definitions verbatim, which contain a harmless duplicate declaration.skipLibCheck: truelets your project type-check cleanly while still fully checking your code against the API.
A first module
import { defineModule, ModuleCategory } from "@protohax/userscript";
defineModule(
{ name: "AutoSprint", category: ModuleCategory.Movement },
(options) => {
const speed = options.number("Speed", 1, {
min: 0, max: 5, step: 0.1, displayResolution: 1,
});
return (ctx) => {
ctx.on("tick", () => {
ctx.session.entityState.localPlayer.strafe(speed.value, 1);
});
};
},
);
That is the whole shape of a module: declare options once, then return a per-session setup function that subscribes to events. The next pages walk through each layer.
Where to go next
- Getting Started — the module lifecycle in detail.
- Modules — metadata, categories, and toggling.
- Options — sliders, toggles, enums, colors.
- Events & Packets — subscribing to the session.
- API Reference — the session, entities, world, inventory, and packets.