Skip to content

minecraft-library/text

Minecraft Text

A Java 21 library that models Minecraft's chat text system - colours, formatting codes, segment trees, click/hover event payloads - and renders it to raw pixel buffers via the vanilla OTF font family.

Important

This project depends on font files derived from copyrighted bitmap assets owned by Mojang AB (a Microsoft subsidiary). The OTF files are never committed to this repository. They are generated on demand by the bundled fonts Gradle task, which invokes minecraft-library/font-generator against the official Minecraft client JAR. You are responsible for ensuring your use of the generated font files complies with the Minecraft EULA and Minecraft Usage Guidelines.

Table of Contents

Features

  • Chat color model - ChatColor.Legacy for vanilla 1.8.9-style codes (0-9, a-f) and ChatColor.Custom for arbitrary modern RGB ("color": "#FF00FF") with automatic shadow derivation via (rgb & 0xFCFCFC) >> 2
  • Formatting codes - ChatFormat enum covering OBFUSCATED, BOLD, STRIKETHROUGH, UNDERLINE, ITALIC, RESET, plus the SECTION_SYMBOL constant and legacy/alternate-code translation helpers
  • Segment primitives - ColorSegment (styled text run), TextSegment (styled run plus click/hover events), and LineSegment (list of styled runs) with builders and legacy-string parsing
  • Event payloads - ClickEvent and HoverEvent with Gson JsonObject (de)serialization
  • Native OTF rendering - MinecraftFont loads the official Minecraft fonts (Regular, Bold, Italic, BoldItalic, Galactic, Illageralt) and rasterizes glyphs into PixelBuffers with zero AWT overhead after initialization
  • Runtime font bootstrap - downstream consumers don't need to ship OTFs: MinecraftFont invokes the generator on first use when the classpath has no fonts/ resources
  • Gson-backed JSON - segment, color, and event types round-trip through JsonObject

Getting Started

Prerequisites

Requirement Version Notes
JDK 21+ Required - the build toolchain targets Java 21
Git 2.x+ Required for cloning and for the fonts task
Python 3.10+ Required only when running the fonts task or the runtime bootstrap

Note

Python is not required to consume this library as a dependency if the upstream artifact already bundles the generated OTFs on its classpath. It is required only when this repository has to produce fresh font files.

Installation

Add the Gradle coordinates via JitPack:

repositories {
    mavenCentral()
    maven(url = "https://jitpack.io")
}

dependencies {
    implementation("com.github.minecraft-library:minecraft-text:<commit-or-tag>")
}

Or clone the repository and build locally:

git clone https://github.com/minecraft-library/minecraft-text.git
cd minecraft-text
./gradlew build

Usage

Build a single styled run and serialize it to JSON:

import lib.minecraft.text.ChatColor;
import lib.minecraft.text.TextSegment;

TextSegment hello = new TextSegment.Builder()
    .withText("Hello, world!")
    .withColor(ChatColor.Legacy.GOLD)
    .isBold()
    .build();

String json = hello.toJson().toString();

Compose multiple styled runs into a single line:

import lib.minecraft.text.ColorSegment;
import lib.minecraft.text.LineSegment;

LineSegment line = LineSegment.builder()
    .withSegments(
        ColorSegment.builder()
            .withText("Hello, ")
            .withColor(ChatColor.Legacy.GOLD)
            .build(),
        ColorSegment.builder()
            .withText("world!")
            .withColor(ChatColor.of(0xFF00FF))
            .isBold()
            .build()
    )
    .build();

Or parse a legacy section-symbol string directly:

// Accepts § natively and '&' as a substitute (second overload lets you pick another substitute)
LineSegment parsed = ColorSegment.fromLegacy("&6Hello, &lworld!");

Render a line to a PixelBuffer:

import dev.simplified.image.pixel.PixelBuffer;
import lib.minecraft.text.font.MinecraftFont;
import lib.minecraft.text.font.MinecraftGraphics;

// Output buffer is sized in native render pixels (mcPixels * MC_PIXEL_SCALE).
PixelBuffer buffer = PixelBuffer.create(256, 32);
MinecraftGraphics gfx = new MinecraftGraphics(buffer);

// drawString takes mcPixel coordinates; the baseline convention matches AWT.
int cursorXMcPx = 0;
int baselineYMcPx = MinecraftFont.REGULAR.getFontMetrics().getAscentMcPixels();

for (ColorSegment segment : line.getSegments()) {
    segment.getColor().ifPresent(c -> gfx.setColor(c.color()));
    gfx.setFont(MinecraftFont.of(segment.fontStyle()));
    gfx.drawString(segment.getText(), cursorXMcPx, baselineYMcPx);
    // Font metrics return native-pixel advances; divide back into mcPixel space.
    cursorXMcPx += gfx.getFontMetrics().stringWidth(segment.getText()) / MinecraftFont.MC_PIXEL_SCALE;
}

Tip

Call MinecraftFont.REGULAR.glyph(codepoint) directly if you need per-glyph bitmaps (e.g. for a custom layout engine). The glyph cache is thread-safe and lazily populated via ConcurrentMap#computeIfAbsent.

Fonts

Runtime Bootstrap

On first use, MinecraftFont resolves each OTF in priority order:

  1. Classpath - fonts/Minecraft-*.otf via ClassLoader.getResourceAsStream
  2. Module cache - cache/fonts/Minecraft-*.otf
  3. On-demand generation - invokes ToolingFonts to clone the generator and produce the OTFs into cache/fonts/ (version driven by MinecraftFont.DEFAULT_VERSION)

This means downstream consumers can depend on minecraft-text without shipping any font assets - the first MinecraftFont.REGULAR.glyph(...) call transparently produces them.

Important

The runtime bootstrap requires git and Python 3.10+ on the host's PATH. In sealed environments (e.g. production Docker images) you should run the build-time generation during image build and ship the OTFs on the classpath instead.

Build-Time Generation

Run the fonts Gradle task to populate cache/fonts/:

./gradlew fonts                      # defaults to Minecraft 26.1
./gradlew fonts -PfontVersion=26.2   # pin a different version

The task clones minecraft-library/font-generator into cache/font-generator/, creates a Python virtual environment, installs the generator, and emits .otf files to cache/fonts/. Subsequent runs reuse the clone and venv so only the generator itself re-executes.

The standard processResources task then copies cache/fonts/ onto the runtime classpath under fonts/:

./gradlew build

Note

cache/ and src/main/resources/fonts/ are both gitignored. The fonts task writes exclusively into cache/fonts/; the source tree is never modified.

Build order for a fresh checkout
./gradlew fonts     # emit cache/fonts/Minecraft-*.otf (run once per version bump)
./gradlew build     # compile, test, and package the jar

You can skip the first step if you are only working on code paths that do not exercise MinecraftFont. Unit tests under MinecraftFontTest will fail without OTFs present.

Packages

Package Purpose
lib.minecraft.text Top-level model - ChatColor, ChatFormat, TextSegment, LineSegment, ColorSegment
lib.minecraft.text.event ClickEvent, HoverEvent payloads with Gson (de)serialization
lib.minecraft.text.font MinecraftFont, MinecraftFontMetrics, MinecraftGraphics - OTF loading and glyph rendering
lib.minecraft.text.tooling ToolingFonts - Gradle/runtime-invoked wrapper around the Python font generator

How It Works

Segment Model

A Minecraft chat line is modelled as a list of styled text runs rather than a recursive tree. Three classes cover the full surface area:

ColorSegment                                # styled text run
  ├── text         (String)
  ├── color        (Optional<ChatColor>)
  └── bold / italic / underlined / obfuscated / strikethrough (boolean)

TextSegment extends ColorSegment            # run + interaction events
  ├── clickEvent   (Optional<ClickEvent>)
  └── hoverEvent   (Optional<HoverEvent>)

LineSegment                                 # an ordered list of runs
  └── segments     (ConcurrentList<ColorSegment>)

ColorSegment.fromLegacy(String) and LineSegment.fromLegacy(String, char) parse legacy section-symbol strings (§6...§l... or a user-chosen substitute) into the model. TextSegment#toJson emits the wire-format JsonObject; TextSegment.fromJson round-trips it back. MinecraftGraphics draws the resulting runs one at a time, picking a font variant via ColorSegment#fontStyle.

Glyph Rendering

Each MinecraftFont enum value wraps a pre-loaded AWT Font and a lazy glyph atlas:

  1. Enum init - the OTF resolves via the runtime bootstrap, AWT loads it at FONT_POINT_SIZE = 16f, font-level metrics (ascent, descent, height) are captured, and printable ASCII (U+0020 - U+007E) is eagerly rasterized so the first render has zero AWT overhead
  2. Lazy rasterization - non-ASCII codepoints are rasterized on first access via ConcurrentMap#computeIfAbsent and cached for subsequent renders
  3. Draw-time tint - glyphs are stored as white-on-transparent PixelBuffers; callers multiply each pixel's alpha against a target colour at draw time, so no Graphics2D is needed after initialization

The OTFs use unitsPerEm = 1024 with 128 units = 1 mcPixel, and MC_PIXEL_SCALE = 2 maps vanilla Minecraft pixels to output pixels at the standard load size.

Project Structure

minecraft-text/
├── src/
│   ├── main/java/lib/minecraft/text/
│   │   ├── ChatColor.java           # Legacy enum + Custom record
│   │   ├── ChatFormat.java          # Bold/italic/etc. enum
│   │   ├── TextSegment.java         # Recursive segment model
│   │   ├── LineSegment.java         # Flattened same-style runs
│   │   ├── ColorSegment.java        # Draw-ready segment
│   │   ├── event/
│   │   │   ├── ClickEvent.java
│   │   │   └── HoverEvent.java
│   │   ├── font/
│   │   │   ├── MinecraftFont.java          # OTF-backed glyph atlas enum
│   │   │   ├── MinecraftFontMetrics.java   # Ascent/descent/advance capture
│   │   │   └── MinecraftGraphics.java      # Line layout + PixelBuffer output
│   │   └── tooling/
│   │       └── ToolingFonts.java           # Gradle + runtime generator wrapper
│   └── test/java/lib/minecraft/renderer/text/
│       ├── ChatColorTest.java
│       └── font/MinecraftFontTest.java
├── build.gradle.kts
├── settings.gradle.kts
├── gradle/libs.versions.toml
├── LICENSE.md
├── COPYRIGHT.md
├── CONTRIBUTING.md
└── README.md

Runtime Directories

Created during execution and excluded from version control:

Directory Contents
cache/font-generator/ Clone of the Python font-generator repo and its virtual environment
cache/fonts/ Generated Minecraft-*.otf files - copied onto the classpath by processResources
build/ Gradle outputs (compiled classes, resources, jar)

Contributing

See CONTRIBUTING.md for development setup, code style conventions, and how to submit a pull request.

License

This project is licensed under the Apache License 2.0 - see LICENSE.md for the full text.

See COPYRIGHT.md for third-party attribution notices, including information about Mojang AB's copyrighted assets and the upstream font-generator tool.

About

Models Minecraft's chat text system - colours, formatting codes, segment trees, click/hover event payloads - and renders it to raw pixel buffers via the vanilla OTF font family.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Contributors

Languages