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.
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)
}World Renderers
Use registerWorldRenderer for camera-relative world drawing. The current helper set includes drawLine3D for simple world-space debug and guide visuals.
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)
}Client UI Messages
For titles, overlays, action bars, toasts, and client sounds, use the client UI helpers instead of a per-frame renderer.
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()
}
}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.
