Mixin
Inject TypeScript callbacks straight into Minecraft methods at runtime — the scripting equivalent of a Fabric mixin, but defined live from a Tessera module (no restart, no .mixins.json).
import { Mixin, ChatLib } from 'ratph6.tessera.api';
// Run code at the start of every client tick.
Mixin.inject("net.minecraft.client.Minecraft", "tick", (ctx) => {
// ... runs on the render thread, before the original body
});
// Cancel a method entirely.
Mixin.inject("net.minecraft.client.player.LocalPlayer", "aiStep", "HEAD", (ctx) => {
ctx.cancel();
});
// Override what a method returns.
Mixin.inject("net.minecraft.client.player.LocalPlayer", "isSprinting", "RETURN", (ctx) => {
ctx.setReturnValue(true);
});Targets are Mojang-mapped binary class names (net.minecraft...) and method names — the same names the rest of the Tessera API uses, which resolve in the dev client. The callback receives a MixinContext.
Injection points: "HEAD" (default) runs before the body and may MixinContext.cancel or MixinContext.setReturnValue; "RETURN" (alias "TAIL") runs at every return and may override the value. Constructors (<init>), abstract and native methods cannot be injected.
Threading: the callback runs on whatever thread the target method runs on. Most client methods run on the render thread (Tessera's JS thread), so GraalJS callbacks are fine there; targeting an off-thread method (e.g. netty) with a GraalJS module will error.
Requirements: runtime instrumentation must be available — launch with -Djdk.attach.allowAttachSelf=true on a full JDK. If it isn't, the first inject call reports a clear error and the rest of Tessera keeps working.
Functions
Inject into the single overload of method whose JVM descriptor matches (e.g. "(Lnet/minecraft/world/entity/Entity;)Z"). Use this to disambiguate overloaded methods; omit it (the other overloads) to hook every method with that name.