ProtoHax UserScript
ProtoHax UserScript lets you write your own ProtoHax client modules in TypeScript. A userscript declares a module (its name and options) and hooks into the live game session: game events, packets, entities and the world, the local player, the inventory, and the raw packet connection.
Your modules show up in the client menu under the Script category, next to the built-in ones. They work just like first-party modules: users can toggle them, tweak their sliders, toggles and color pickers, and they can read and drive the game the same way.
The @protohax/userscript package
All the types come from one npm package:
@protohax/userscript.
The API is still at 0.x and still taking shape. Any release can include breaking changes until 1.x. Expect to update your scripts between client versions, and pin the package version your script was built against.
The package is types-only: a single index.d.ts, no runtime code. That's
on purpose.
- Types describe the authoring API and the host's game model. Your editor
autocompletes things like
ctx.session.entityState.localPlayer.inventoryand type-checks every packet payload. - Values you import (
defineModule,moduleManager, the entity classes,AbstractBlockLocationTracker,nbt,utils) are resolved at runtime to the host's live singletons once your script is bundled into the client. Your script and the client share one game state, one module manager, and one (patched)prismarine-nbt.
So you install the package for the types, and the client supplies the implementation when your script runs.
Install
The easiest start is the template repository. It comes with the bundler, the deploy script, and a working example module:
git clone https://github.com/hax0r31337/ProtoHax-UserScript-Template my-script
cd my-script
npm install
npm run build
Or add the package to an existing project:
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
}
}
skipLibCheck onVersions before 0.5 need it: their .d.ts copies the host's packet definitions
verbatim, including a harmless duplicate declaration. From 0.5 on the
declarations type-check cleanly, but skipLibCheck: true is still
recommended. Your own code is fully checked against the API either way.
Your script ships as a single ES module with @protohax/userscript left
external. That import is what connects your script to the host's live
singletons. Project Setup covers the bundler config
and where the built file goes.
A first module
import { defineModule } from "@protohax/userscript";
defineModule(
{ name: "AutoSprint" },
{
speed: { type: "number", def: 1, min: 0, max: 5, step: 0.1 },
},
(ctx) => {
// The game's own tick, fired from native before the player moves.
// Position and motion you write here apply in that same tick.
ctx.on("movement_tick", (state) => {
state.strafe(ctx.options.speed.value, 1);
});
},
);
That's the whole shape of a module: a schema that declares the options
once, and a setup function that runs per session, reads the options from
ctx.options, and subscribes to events. The next pages go through each part.
Where to go next
- Project Setup: the template, bundling, and installing your script.
- Getting Started: the module lifecycle in detail.
- Modules: metadata, the Script category, and toggling.
- Options: sliders, toggles, enums, colors.
- Events & Packets: subscribing to the session.
- Movement:
movement_tick,MovementState, jumping, and sprint and sneak control. - Input:
input_tick,InputState, and overriding the player's keys. - API Reference: the session, entities, world, inventory, and packets.