Skip to content

Text and Fonts

KabanFriends edited this page Aug 27, 2026 · 1 revision

Both widgets draw text the way the game does: 8 pixel glyphs on a 9 pixel line, with the 1 pixel drop shadow where the game uses one. This page covers what you can write in a text field, how translations work, and how to change the font.

Text components

Every text field in a bundle is a vanilla JSON text component. Advancement titles and descriptions come from your datapack unchanged. Item tooltips and GUI label texts come from the files you write for the item GUI.

Three forms are accepted, the same three the game accepts:

"Diamond Sword"
["Diamond Sword", { "text": " (sharp)", "color": "gray", "italic": true }]
{ "translate": "item.minecraft.diamond_sword", "color": "aqua" }

An array joins its parts, and each part inherits the style of the one that opened it. An object may carry extra for the same effect.

Fields that change appearance

Field Effect
color A Minecraft colour name, #RRGGBB, or #RGB. reset clears an inherited colour.
bold Bold.
italic Italic.
underlined Underline.
strikethrough Line through.

The sixteen Minecraft colour names are the ones the game uses, from black and dark_blue through yellow and white. An unrecognised colour value inherits instead of failing.

obfuscated and font parse without error but have no visual effect. Click events, hover events, and insertion are ignored, because nothing here is interactive in the game's sense.

Fields that produce text

Field Effect
text A literal string.
translate A translation key, resolved as described below.
with Arguments substituted into the pattern at %s and %N$s.
fallback Used when the key is missing from every language file.
extra Child components, appended, inheriting this component's style.

keybind, score, selector, and nbt render a placeholder. They describe live game state, and a static page has none.

Translations

A translate component resolves in this order:

  1. The language files you supplied, last file first.
  2. The component's own fallback, if it has one.
  3. The key itself.

So a tree built from a vanilla datapack with no language file shows advancements.story.root.title on screen. That is the signal that translations are missing, not a bug.

You have two ways to supply them, and they solve different problems.

Bake at build time

Pass --bake-lang <file.json> to the preprocessor. Every translate component in the bundle is replaced with the finished string, so the bundle carries its own text and needs nothing at runtime.

--bake-lang en_us.json

Use this when the embed shows one language. It is one fewer request, one fewer thing to host, and one fewer way for the page to render keys.

The cost is that the strings are now literal. A runtime language file cannot override a baked bundle, so switching languages means building one bundle per language.

Arguments in with are baked as plain strings, so an argument that carried its own colour or style loses it. Literal %% and positional %N$s both bake correctly.

Supply at runtime

Serve a language JSON file and point the widget at it. Repeat the setting to layer files, with later files winning.

In a query string:

&lang=https://example.com/lang/en_us.json&lang=https://example.com/lang/server.json

In JavaScript:

langUrls: [
  "https://example.com/lang/en_us.json",
  "https://example.com/lang/server.json",
]

Use this when one bundle has to serve several languages, or when your own strings change more often than your advancements do. A base file plus a small override file is the usual shape.

Language files are fetched by the page that runs the widget, so a file on another origin must send Access-Control-Allow-Origin.

The file format

The same flat object the game uses. Nothing else is needed.

{
  "advancements.story.root.title": "Minecraft",
  "advancements.story.mine_stone.title": "Stone Age",
  "advancements.story.mine_stone.description": "Mine Stone with your new Pickaxe"
}

Vanilla keys for advancements follow advancements.<tab>.<name>.title and .description. Your own datapack decides its own keys.

Fonts

The widgets ship Minecraft Seven, a pixel font that matches the game's metrics, and use it unless you say otherwise. It is served from the core assets directory, which is what coreAssetBase points at.

Use a font the page already has

Set font to a CSS font family:

&font=monospace
font: "'My Pixel Font', monospace"

In an iframe embed this only reaches fonts the iframe itself can resolve, which in practice means system and generic families. Your page's @font-face rules do not cross into the frame.

Load a font file

Set fontUrl to a TTF, OTF, or WOFF2 file. The widget adds the @font-face rule for you.

&fontUrl=https://example.com/fonts/my-pixel-font.ttf
fontUrl: "https://example.com/fonts/my-pixel-font.ttf",
font: "monospace",

Given both, font is the fallback family while the file loads. Font files must be served over http:, https:, data:, or blob:, and they need the usual cross-origin font headers when they come from another host.

Text is measured, wrapped, and positioned from the font's real metrics, so the widget re-lays out once a web font finishes loading. A font whose glyphs are not 8 pixels wide still works. Lines wrap at different points, and tooltips come out a different width.

Clone this wiki locally