Skip to content

Rendering

goshi-hider edited this page Jul 24, 2026 · 1 revision

Rendering

Package: dev.goshi.omnimixin.api.event.render

Client-only. Every class in this package is annotated @Environment(EnvType.CLIENT) and will not exist on a dedicated server. Register all of these from ClientModInitializer.onInitializeClient(), not your regular ModInitializer — see Getting Started for why that split matters.

PlayHud

PRE_HUD and POST_HUD let you draw under or over the vanilla HUD every frame.

PlayHud.POST_HUD.register(ctx -> {
    DrawContext draw = ctx.context();
    draw.drawText(
            MinecraftClient.getInstance().textRenderer,
            "Custom overlay text", 10, 10, 0xFFFFFF, true
    );
});

HudContext(DrawContext context)

PRE_HUD fires before vanilla draws anything, so whatever you draw sits underneath the vanilla HUD. POST_HUD fires after, so you draw on top.

PlayScreen

Three events across a screen's lifecycle: OPEN (can be vetoed), INIT (fires after a screen builds its widgets), and CLOSE.

// Block the crafting table screen from opening while in combat.
PlayScreen.OPEN.register(ctx -> {
    if (ctx.newScreen() instanceof CraftingScreen && isInCombat(MinecraftClient.getInstance().player)) {
        ctx.cancel().cancel();
    }
});

// Add a custom button to every inventory-style screen after it initializes.
PlayScreen.INIT.register(ctx -> {
    if (ctx.screen() instanceof HandledScreen<?> handled) {
        // handled.addDrawableChild(new MyCustomButton(...));
    }
});

ScreenOpenContext(Screen newScreen, Screen previousScreen, Cancellable cancel)OPEN

ScreenContext(Screen screen)INIT / CLOSE

newScreen()/previousScreen() (and screen() for CLOSE) can be null — vanilla itself represents "no screen open" as a null Screen, so check for that if your logic cares about closing back to nothing.

PlayCamera.CALCULATE_FOV

Adjusts the player's field of view for the frame.

// Slight FOV pull-in while aiming down sights with a custom weapon.
PlayCamera.CALCULATE_FOV.register(ctx -> {
    if (isAimingCustomWeapon(MinecraftClient.getInstance().player)) {
        ctx.modifier().add(-10.0);
    }
});

FovContext(Camera camera, double baseFov, MutableDouble modifier)

Vanilla's own sprint-FOV boost is already baked into baseFov by the time this fires, so there's no separate sprint-FOV event — this one hook covers both cases.

PlayRender

PRE_ENTITY and POST_ENTITY fire immediately before and after vanilla renders a given entity for the current frame.

// Hide any entity tagged as "vanished" (e.g. a custom invisibility system
// that isn't tied to vanilla's own Invisibility status effect).
PlayRender.PRE_ENTITY.register(ctx -> {
    if (isVanished(ctx.entity())) {
        ctx.cancel().cancel();
    }
});

// Draw a custom glow outline right after a marked entity renders.
PlayRender.POST_ENTITY.register(ctx -> {
    if (isQuestTarget(ctx.entity())) {
        drawGlowOutline(ctx.matrices(), ctx.vertexConsumers(), ctx.light());
    }
});

RenderContext(Entity entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, Cancellable cancel)

matrices() is still positioned for entity when POST_ENTITY fires, so you can draw relative to it without recalculating the transform yourself. Cancelling from PRE_ENTITY skips vanilla's render for that entity that frame; POST_ENTITY's cancel() is a no-op, since the render has already happened by the time it fires.

Note: this covers per-entity rendering only. A hook at the very end of the whole world render pass (WORLD_LAST) isn't implemented yet — that particular vanilla method has one of the largest and most version-volatile parameter lists in the game, and it wasn't something this pass could verify with enough confidence to ship responsibly. See Known Limitations.

Clone this wiki locally