AgentStack
SKILL verified MIT Self-run

Libgdx Freetype

skill-kyu-n-gdx-claude-skills-libgdx-freetype · by kyu-n

Use when writing libGDX Java/Kotlin code that generates BitmapFont at runtime from .ttf/.otf files using gdx-freetype — FreeTypeFontGenerator, FreeTypeFontParameter, font size/color/border/shadow configuration, characters parameter for i18n, incremental glyph rendering for CJK, AssetManager integration with FreeTypeFontLoader, or density-scaled font sizes. Use when debugging missing glyphs, blurr…

No reviews yet
0 installs
12 views
0.0% view→install

Install

$ agentstack add skill-kyu-n-gdx-claude-skills-libgdx-freetype

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Libgdx Freetype? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

libGDX gdx-freetype

Runtime BitmapFont generation from .ttf/.otf files. Use instead of pre-baking fonts with Hiero when you need multiple sizes, dynamic scaling, or user-selectable fonts.

Gradle Dependencies

// core
implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"

// desktop
implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"

// android (all four ABIs)
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a"
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a"
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86"
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64"

// iOS
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-ios"

The platform artifact is gdx-freetype-platform, not gdx-freetype. Missing platform natives causes UnsatisfiedLinkError at runtime.

iOS/RoboVM: Also add to robovm.xml inside ``:


    com.badlogic.gdx.graphics.g2d.freetype.**

Without this, RoboVM's AOT compiler strips FreeType classes, causing runtime crashes on iOS.

Basic Usage

FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/myfont.ttf"));

FreeTypeFontParameter parameter = new FreeTypeFontParameter();
parameter.size = (int)(24 * Gdx.graphics.getDensity());  // density-scaled
parameter.color = Color.WHITE;
parameter.borderWidth = 1;
parameter.borderColor = Color.BLACK;
parameter.minFilter = Texture.TextureFilter.Linear;
parameter.magFilter = Texture.TextureFilter.Linear;
parameter.characters = FreeTypeFontGenerator.DEFAULT_CHARS;  // ASCII + common punctuation

BitmapFont font = generator.generateFont(parameter);
generator.dispose();  // safe — the font is independent of the generator
// font remains fully usable after generator disposal

FreeType requires an OpenGL context. It bakes glyphs into a texture atlas. It does not work in the headless backend or before create().

FreeTypeFontGenerator is NOT thread-safe. Generating fonts from multiple threads simultaneously crashes. AssetManager handles synchronization internally, but manual multi-threaded generation will fail.

Key Parameter Fields

| Field | Default | Description | |---|---|---| | size | 16 | Pixel height. Scale with Gdx.graphics.getDensity() for consistent physical size across devices. | | characters | DEFAULT_CHARS | Which glyphs to bake. ASCII by default — add accented chars for European languages, or use incremental for CJK. | | color | Color.WHITE | Font fill color | | borderWidth | 0 | Outline thickness in pixels | | borderColor | Color.BLACK | Outline color | | shadowOffsetX/Y | 0 | Drop shadow offset | | shadowColor | Color(0,0,0,0.75f) | Drop shadow color | | minFilter / magFilter | Nearest | Texture filtering. Use Linear for smooth scaled text. | | hinting | AutoMedium | None, Slight, Medium, Full, AutoSlight, AutoMedium, AutoFull. Default is best for most fonts. Use None for pixel art fonts; Full can cause artifacts with some fonts. | | kerning | true | Adjust spacing between glyph pairs | | mono | false | Monospace rendering (all glyphs same width) | | genMipMaps | false | Generate mipmaps for minification | | incremental | false | Render glyphs on demand instead of all at once — see CJK section |

Disposal Lifecycle

Generator and font are independent. After generateFont(), the font owns its own texture. The generator is no longer needed.

// Generate multiple sizes from one .ttf, then dispose generator
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("font.ttf"));

FreeTypeFontParameter param = new FreeTypeFontParameter();
param.size = 16;
BitmapFont small = generator.generateFont(param);
param.size = 24;
BitmapFont medium = generator.generateFont(param);
param.size = 48;
BitmapFont large = generator.generateFont(param);

generator.dispose();  // fonts remain usable

// In dispose():
small.dispose();
medium.dispose();
large.dispose();

Exception — incremental mode: When parameter.incremental = true, the generator must stay alive because it renders new glyphs on demand. Dispose the generator only after disposing the font. See CJK section below.

Generated BitmapFonts are managed textures — they auto-reload after Android GL context loss like any other managed resource. Do NOT re-run the generator in resume() to "reload" fonts.

Characters Parameter (i18n)

DEFAULT_CHARS covers basic ASCII. For European languages, add accented characters:

parameter.characters = FreeTypeFontGenerator.DEFAULT_CHARS
    + "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ"
    + "ŁłŃńŚśŹźŻżŒœ¿¡«»";

Characters not in the set render as missing glyphs. If text looks broken, check this parameter first.

Atlas size: The default atlas page is 1024x1024. Large character sets without incremental mode can fill it, silently dropping glyphs. For large sets, either use incremental = true or provide a larger packer: parameter.packer = new PixmapPacker(2048, 2048, Pixmap.Format.RGBA8888, 1, false);

Incremental Rendering (CJK)

CJK character sets have thousands of glyphs. Baking them all upfront creates enormous textures and long load times. Use incremental mode instead:

FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/NotoSansCJK.ttf"));
FreeTypeFontParameter param = new FreeTypeFontParameter();
param.size = 24;
param.incremental = true;  // glyphs rendered on first use
param.characters = "";     // start empty — glyphs added on demand

BitmapFont cjkFont = generator.generateFont(param);
// DO NOT dispose generator — it's needed to render new glyphs

With incremental = true:

  • Glyphs are baked into the atlas the first time they're drawn
  • The generator MUST stay alive — dispose it only after the font
  • Small hitch on first render of each new glyph
  • Pre-load common characters during a loading screen to reduce hitches
// Dispose order for incremental fonts
cjkFont.dispose();
generator.dispose();  // AFTER the font

AssetManager Integration

Register the FreeType loaders, then load fonts asynchronously:

AssetManager assets = new AssetManager();

// Register loaders (once, at startup)
assets.setLoader(FreeTypeFontGenerator.class,
    new FreeTypeFontGeneratorLoader(assets.getFileHandleResolver()));
assets.setLoader(BitmapFont.class, ".ttf",
    new FreetypeFontLoader(assets.getFileHandleResolver()));

// Queue a font for loading
FreetypeFontLoader.FreeTypeFontLoaderParameter params =
    new FreetypeFontLoader.FreeTypeFontLoaderParameter();
params.fontFileName = "fonts/myfont.ttf";           // actual .ttf path
params.fontParameters.size = (int)(24 * Gdx.graphics.getDensity());
params.fontParameters.minFilter = Texture.TextureFilter.Linear;
params.fontParameters.magFilter = Texture.TextureFilter.Linear;

assets.load("myfont-24.ttf", BitmapFont.class, params);  // key is arbitrary, not a file path

// In render loop:
if (assets.update()) {
    BitmapFont font = assets.get("myfont-24.ttf", BitmapFont.class);
}

The asset key (first argument to load()) doesn't need to match the actual .ttf filename, but it must end in .ttf — the FreeType loader is registered for the .ttf extension. A key like "heading-font" without .ttf won't match the loader and silently fails to load.

Density Scaling

Scale font size by screen density so text appears the same physical size across devices:

parameter.size = (int)(24 * Gdx.graphics.getDensity());
// mdpi (1.0) → 24px, xhdpi (2.0) → 48px, xxhdpi (3.0) → 72px

Common Mistakes

  1. Wrong platform artifact name — The natives artifact is gdx-freetype-platform, not gdx-freetype. Using the wrong name compiles fine but crashes with UnsatisfiedLinkError at runtime.
  2. Disposing generator before generating the font — The generator must be alive when generateFont() is called. Dispose it after.
  3. Thinking font disposal is tied to generator disposal — They're independent. Disposing the generator does NOT affect already-generated fonts (unless using incremental mode).
  4. Disposing generator in incremental mode — When incremental = true, the generator must stay alive to render new glyphs on demand. Dispose the generator only after the font.
  5. Missing characters for i18nDEFAULT_CHARS is ASCII only. European accented characters (é, ñ, ü) must be added explicitly or they render as missing glyphs.
  6. Not knowing about incremental for CJK — Baking all CJK glyphs upfront creates huge textures. Use parameter.incremental = true for on-demand rendering.
  7. Suggesting Hiero when runtime generation is needed — Hiero pre-bakes fonts at build time. Use FreeType when sizes must be computed at runtime (density scaling, user preferences).
  8. Missing platform natives in Gradle — The core gdx-freetype dependency alone is not enough. Each platform needs its gdx-freetype-platform natives or FreeType crashes at runtime.
  9. Missing robovm.xml forceLinkClasses for iOS — RoboVM strips FreeType classes without this entry. App compiles but crashes on iOS.
  10. Hardcoding pixel size without density scalingparameter.size = 24 looks different on every device. Use (int)(24 * Gdx.graphics.getDensity()) for consistent physical size.
  11. Using FreeType in headless backend — FreeType bakes glyphs into a GL texture atlas. It requires an OpenGL context and does not work in headless mode.
  12. Re-running generator in resume() on Android — Generated BitmapFonts are managed textures and auto-reload after GL context loss. Regenerating wastes time and leaks the old font.
  13. AssetManager key without .ttf extension — The FreeType loader is registered for .ttf. A key like "heading-font" won't match — use "heading-font.ttf" instead.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.