libgdx-freetype — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited libgdx-freetype (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
// 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 <config>:
<forceLinkClasses>
<pattern>com.badlogic.gdx.graphics.g2d.freetype.**</pattern>
</forceLinkClasses>Without this, RoboVM's AOT compiler strips FreeType classes, causing runtime crashes on iOS.
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 disposalFreeType 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.
| 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 |
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.
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);
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 glyphsWith `incremental = true`:
// Dispose order for incremental fonts
cjkFont.dispose();
generator.dispose(); // AFTER the fontRegister 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.
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) → 72pxgdx-freetype-platform, not gdx-freetype. Using the wrong name compiles fine but crashes with UnsatisfiedLinkError at runtime.generateFont() is called. Dispose it after.incremental = true, the generator must stay alive to render new glyphs on demand. Dispose the generator only after the font.DEFAULT_CHARS is ASCII only. European accented characters (é, ñ, ü) must be added explicitly or they render as missing glyphs.parameter.incremental = true for on-demand rendering.gdx-freetype dependency alone is not enough. Each platform needs its gdx-freetype-platform natives or FreeType crashes at runtime.parameter.size = 24 looks different on every device. Use (int)(24 * Gdx.graphics.getDensity()) for consistent physical size..ttf. A key like "heading-font" won't match — use "heading-font.ttf" instead.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.