Skip to content

1.20.1 Callbacks

hp-1e edited this page Nov 3, 2026 · 1 revision

English | 中文

Callbacks (1.20.1 Forge)

Callbacks let a script draw or add tooltips with its own logic, for example a mana bar whose length comes from recipe data.

event.create('mypack:library', cat => cat
  // ...
  .onDraw(ctx => {
    let mana = ctx.recipe.getData('mana')
    if (mana != null) {
      ctx.fill(4, 24, 18, 3, 0x2040A0)
      ctx.text(4, 28, Text.of(`${mana}`), 0x2040A0)
    }
  })
  .onTooltip(ctx => {
    if (ctx.isHovered(4, 24, 18, 12)) {
      ctx.tooltip(Text.aqua(`Mana: ${ctx.recipe.getData('mana')}`))
    }
  }))

// in registerRecipes
event.add('mypack:library', r => r.slot('book', 'minecraft:enchanted_book').data('mana', 500))
Callback When it runs
onDraw(ctx => ...) Every frame, after all other elements of the page are drawn
onTooltip(ctx => ...) While the mouse is over the category. Add lines with ctx.tooltip(...).
scrollPanel(..., ctx => ...) Every frame, inside the panel (see Drawing)

The ctx object

Coordinates are relative to the category (or to the panel content inside scrollPanel).

Member What it is
ctx.recipe The recipe being drawn. ctx.recipe.getData(key) reads values set with r.data(key, value).
ctx.mouseX, ctx.mouseY Mouse position
ctx.isHovered(x, y, w, h) true if the mouse is inside the rectangle
ctx.tick Game time in ticks, for your own animations: ctx.tick % 40
ctx.text(x, y, text[, color[, shadow]]) Draws text
ctx.fill(x, y, w, h, color) Draws a filled rectangle. 0xRRGGBB is opaque; use 0xAARRGGBB for transparency.
ctx.item(stack, x, y) Draws an item icon (display only, not clickable)
ctx.texture(tex, x, y, u, v, w, h[, texW, texH]) Draws part of a texture, same arguments as texture but with the texture first
ctx.tooltip(text) Adds a tooltip line (only inside onTooltip)
ctx.graphics Minecraft's raw GuiGraphics, for anything not covered above. It is null inside onTooltip.

Drawing methods do nothing inside onTooltip, and ctx.tooltip does nothing inside onDraw.

Performance and errors

  • onDraw runs every frame for every visible recipe. Do not search registries or build large lists inside it. Prepare values in registerRecipes and pass them with r.data(...).
  • If a callback throws, it is turned off for that category and the error is logged once, so the log is not flooded. It comes back after the next reload (F3+T, then /reload).

Clone this wiki locally