Skip to content
On this page

HUD and World Renderers

WARNING

HUD and world render callbacks run on Fabric and NeoForge clients only.

HUD renderers draw in screen space. World renderers draw in the client world each frame. Both APIs use stable string ids, so registering the same id again replaces the old callback; client reload also clears script-owned render callbacks.

Detailed signatures live in the KattonClientRenderApi.

HUD Renderers

Use registerHudRenderer from a @ClientScriptEntrypoint. The callback receives a HudRenderContext, which is passed to helpers such as drawHudText, fillHudRect, and drawHudTexture.

kotlin
import top.katton.api.*

@ClientScriptEntrypoint(ClientPhase.JOINED)
fun hudRenderTestMain() {

    registerHudRenderer("katton:test:hud", HudRenderLayer.FOREGROUND, 20) { ctx ->
        fillHudRect(ctx, 6, 6, 258, 64, 0xAA000000.toInt())
        fillHudRect(ctx, 8, 8, 256, 62, 0x66002244)

        drawHudText(ctx, "Katton HUD Render Test", 14, 14, 0xFFE8F1FF.toInt(), true)
        drawHudText(ctx, "FPS: ${clientFps()}", 14, 28, 0xFF9BD5FF.toInt(), false)
        drawHudText(ctx, "Screen: ${clientScreenName() ?: "In-World"}", 14, 40, 0xFFB5FFC5.toInt(), false)

        val p = clientPos()
        if (p != null) {
            drawHudText(ctx, "Pos: %.2f, %.2f, %.2f".format(p.x, p.y, p.z), 14, 52, 0xFFFFD38A.toInt(), false)
        }
    }
    clientTell("[Katton] HUD render test script loaded", overlay = false)
}
Example of rendering text on the HUD

World Renderers

Use registerWorldRenderer for camera-relative world drawing. The current helper set includes drawLine3D for simple world-space debug and guide visuals.

kotlin
import top.katton.api.*

@ClientScriptEntrypoint(ClientPhase.JOINED)
fun worldRenderTestMain() {
    registerWorldRenderer("katton:test:world", WorldRenderLayer.NORMAL, 0) { ctx ->
        val pos = clientPos() ?: return@registerWorldRenderer

        val x = pos.x
        val y = pos.y + 1.6
        val z = pos.z

        // X axis — red
        drawLine3D(
            ctx,
            x - 1.0, y, z,
            x + 1.0, y, z,
            argbColor = 0xFFFF5050.toInt(),
            lineWidth = 2.0f
        )

        // Y axis — green
        drawLine3D(
            ctx,
            x, y - 1.0, z,
            x, y + 1.0, z,
            argbColor = 0xFF50FF9E.toInt(),
            lineWidth = 2.0f
        )

        // Z axis — blue
        drawLine3D(
            ctx,
            x, y, z - 1.0,
            x, y, z + 1.0,
            argbColor = 0xFF5BB4FF.toInt(),
            lineWidth = 2.0f
        )
    }

    clientTell("[Katton] World render test script loaded", overlay = false)

}
3D graphics rendering example

Client UI Messages

For titles, overlays, action bars, toasts, and client sounds, use the client UI helpers instead of a per-frame renderer.

kotlin
import net.minecraft.client.gui.components.toasts.SystemToast
import top.katton.api.*

@ClientScriptEntrypoint(ClientPhase.JOINED)
fun clientUiSmokeTestMain(){
    runOnClient {
        clientTell("[Katton] Starting client UI test")
        clientTitleTimes(fadeInTicks = 8, stayTicks = 30, fadeOutTicks = 10)
        clientTitle("Katton Client API")
        clientSubtitle("UI smoke test")

        clientOverlay("Overlay message from script", tinted = true)
        clientActionBar("Action bar notification")
        clientNowPlaying("Current music track hint")
        clientAddSystemToast(SystemToast.SystemToastId.NARRATOR_TOGGLE, "Toast fallback test", "If no specific toast path is found, this message will be displayed.")

        playClientSound("minecraft:entity.experience_orb.pickup", volume = 0.8f, pitch = 1.0f)

        // Clear overlay after a short delay (triggered via script execution)
        clearClientOverlay()
    }
}
Message and notification display

Cleanup

Use unregisterHudRenderer(id) or unregisterWorldRenderer(id) when a renderer should stop before the next reload. Use unique ids per feature so independent scripts do not replace one another accidentally.