# Libgdx Development Libgdx Architect

> Build cross-platform 2D and 3D games in Java or Kotlin. TRIGGER WHEN: scaffolding, coding, or debugging a libGDX project: gdx-liftoff vs gdx-setup, Game/Screen/ApplicationListener structure, Scene2D, Ashley ECS, Box2D, Tiled maps, AssetManager and OpenGL disposal, TexturePacker, GL thread blocking, frame-rate drops, version migration, or multi-platform Gradle builds.

- Skill: `acaprino/libgdx-development-libgdx-architect` (Agent Skill)
- Install (CLI): `npx skillmds@latest add acaprino/libgdx-development-libgdx-architect`
- Raw SKILL.md: https://api.skillmd.com/api/skills/acaprino/libgdx-development-libgdx-architect/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: acaprino (https://skillmd.com/u/acaprino)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/acaprino/libgdx-development-libgdx-architect

---


<!-- Generated by the Daodan compiler for pi. Edit the kernel, never this file. -->

# Expert libGDX Game Development Architect

Architect for cross-platform 2D and 3D games built on libGDX. Project generation, rendering pipeline, game architecture, asset and screen lifecycle, multi-platform deployment.

## Core Knowledge

### libGDX Architecture
- Cross-platform Java game framework targeting Desktop (LWJGL3), Android, iOS (RoboVM), HTML5 (GWT)
- OpenGL ES 2.0/3.0 abstraction layer via `Gdx.gl` / `Gdx.gl20` / `Gdx.gl30`
- Application lifecycle: `ApplicationListener` (create, resize, render, pause, resume, dispose) wraps a `Game` or custom root class
- `Game` class manages multiple `Screen` instances; each Screen has its own show/render/hide/dispose lifecycle
- Static `Gdx` class exposes platform-specific implementations: `Gdx.app`, `Gdx.graphics`, `Gdx.input`, `Gdx.audio`, `Gdx.files`, `Gdx.net`
- Current stable: libGDX 1.14.0 (released 2025-10-20); previous 1.13.5 (2025-05). Roughly 5-month release cadence, project is actively maintained
- LWJGL3 default bumped to 3.4.1 in 1.14.0 to support Java 25+

### Project Generation
- `gdx-liftoff` is the official current generator under the `libgdx` org. Replaces the legacy `gdx-setup.jar`
- Provides a Swing GUI for platform selection, third-party extensions (Ashley, Artemis-ODB, Box2D, FreeType, Controllers, gdx-vfx, gdx-pay), template selection, and language choice (Java, Kotlin, Scala, Clojure)
- Generates a multi-module Gradle project: `core/`, `lwjgl3/`, `android/`, `ios/`, `html/` modules with a shared root build
- Latest gdx-liftoff baseline: Kotlin 2.3.21, Gradle 9.5.0, Java 21 target with Java 17 as minimum
- Download from https://github.com/libgdx/gdx-liftoff/releases as a runnable JAR

### Language Choice
- Java is the safe default and only fully-supported option for every backend including GWT/HTML
- Kotlin is community-recommended for shorter code (~20% reduction reported by Unciv project), null-safety, and functional patterns with no measurable performance cost
- Kotlin is incompatible with the GWT/HTML backend. Use Java for HTML targets, or use TeaVM (work-in-progress) as the Kotlin-compatible web alternative
- Scala and Clojure are supported by gdx-liftoff but rarely used in practice

### Game Architecture Patterns
- `Game` + multiple `Screen` is the standard structure for menu, gameplay, pause, and game-over states
- Scene2D handles UI rendering, input routing, hit detection, and layout via `Stage` and `Actor`
- Ashley ECS handles game-world entities and logic via `Engine`, `Entity`, `Component`, `System`
- Community consensus: use Scene2D and Ashley in parallel, not as alternatives. Scene2D for UI/input, Ashley for world state and logic
- Box2D for 2D physics: `World`, `Body`, `Fixture`. Fixed timestep simulation (e.g. 60 Hz) decoupled from render rate
- bullet for 3D physics; libGDX includes a Java wrapper

### Rendering Pipeline
- `SpriteBatch` batches sprite draws by texture; `ShapeRenderer` for primitives; `ModelBatch` for 3D
- `OrthographicCamera` for 2D, `PerspectiveCamera` for 3D; viewport (FitViewport, FillViewport, ScreenViewport, StretchViewport, ExtendViewport) handles resize and aspect ratio
- Texture binding switches are the dominant performance cost. Pack all sprites into power-of-two atlases (typically 2048x2048) with TexturePacker and order draw calls by texture, not by entity
- Profiling stop signal: when `glClear` dominates the profiler, you have hit the vsync ceiling. Code optimization beyond that point will not increase frame rate
- Frame-budget guideline: 16.6 ms at 60 fps, 8.3 ms at 120 fps. Render thread must never block

### Asset and Resource Management
- `AssetManager` handles async asset loading via a worker thread; call `update()` every frame and act when it returns `true`
- Never make AssetManager (or any Texture, Sound, Music, Stage) a static field. Android process lifecycle does not match the JVM static lifecycle and leads to missing textures or stale references on resume
- OpenGL resources are NOT managed by the JVM garbage collector. Every Texture, Sound, Music, ShaderProgram, Stage, Skin, TextureAtlas, BitmapFont, ParticleEffect MUST be explicitly `.dispose()`d. Failure leaks VRAM until the device runs out
- AssetManager async worker has a known inefficiency where one `update()` per frame is too slow during loading screens; call `update()` multiple times per frame on dedicated loading screens
- Avoid `finishLoadingAsset()` in blocking mode combined with `AbsoluteFileHandleResolver`: deadlock pattern reported in libgdx#4888

### Screen Lifecycle
- Reuse Screen instances across transitions rather than constructing new ones each time. Construction reallocates assets; resetting state is cheaper
- Set `Gdx.input.setInputProcessor()` in the Screen's `show()` method, not the constructor. Constructor runs before the screen is visible
- Always call `dispose()` on the previous Screen when the Game switches screens permanently. The `Game.setScreen()` default does NOT auto-dispose; you must manage that explicitly
- For transition animations, the community-standard library is `crykn/libgdx-screenmanager`. It auto-registers and deregisters input processors on show/hide

### Scene2D Performance
- `Group.isTransform` defaults to `true` but costs measurable CPU on every frame for transform matrix pushes. Set `isTransform = false` on any Group that does not rotate or scale
- Subclassing actors to no-op `act()`, `draw()`, and `hit()` when not needed (the `ActionlessGroup` community pattern) eliminates per-frame overhead for large static UI trees
- Use `Skin` JSON files for theming; freetype-gdx for runtime BitmapFont generation from TTF (saves bundling rasterized fonts)

### Ashley ECS Pitfalls
- Components that hold collections (arrays, maps) MUST implement `Poolable` and clear those collections in `reset()`. Pooled components otherwise retain dangling references and prevent GC of textures
- Mapper pattern: `ComponentMapper<MyComponent> mapper = ComponentMapper.getFor(MyComponent.class)`; cache the mapper, do not call `getFor()` per-frame
- `Family.all(...).get()` returns a filtered entity iterable; iterate in `EntitySystem.update()`

### GL Thread Safety
- Render thread is the ONLY thread allowed to touch OpenGL resources or call `Gdx.gl.*`
- IO, network, heavy computation MUST run on a worker thread. Use `Gdx.app.postRunnable(...)` to push results back to the render thread
- Blocking the render thread causes ANR on Android and tanks frame rate on desktop

### libGDX 1.14.0 Breaking Changes
- `Pools` API was reverted then deprecated in favor of new `PoolManager`. Migrate `Pools.obtain(...)` / `Pools.free(...)` usages
- `JsonValue#get` lost case-insensitive lookup; case must now match exactly
- Tiled map loader unified: `TmxMapLoader` and `AtlasTmxMapLoader` plus class and template object support
- LWJGL3 default updated to 3.4.1 for Java 25+ compatibility
- See https://libgdx.com/news/2025/10/gdx-1-14-0 for the full changelog

### Platform Targets
- **Desktop (LWJGL3)**: Java 17+ runtime, Java 21 recommended. Native window via GLFW. Output: runnable JAR or jpackage native installer
- **Android**: minSdk typically 21+, targetSdk 34+ (2025-2026 recommendation). Android Studio handles signing. Game thread runs on the GLSurfaceView thread
- **iOS (RoboVM)**: Java 8 language level cap is a permanent constraint. RoboVM AOT-compiles Java bytecode to native ARM. Xcode required, macOS-only builds
- **HTML5 (GWT)**: Java only (no Kotlin). Slower build, browser audio/input constraints. TeaVM is the Kotlin-compatible alternative with WIP libGDX support

## Decision Frameworks

### Language Choice
| Context | Language |
|---------|----------|
| Desktop + Android only | Kotlin (recommended) |
| HTML5 target required | Java (Kotlin incompatible with GWT) |
| iOS + HTML5 | Java (also caps you at Java 8 source level for iOS) |
| Maximum tooling support | Java |
| Smallest code base | Kotlin |

### Architecture Pattern
| Game Type | Recommended Stack |
|-----------|------------------|
| Simple arcade/puzzle | Game + Screen + SpriteBatch + Scene2D for UI |
| Mid-size action/RPG | Game + Screen + Scene2D (UI) + Ashley ECS (world) |
| Physics-driven | Add Box2D with fixed timestep stepping |
| 3D | ModelBatch + Environment + Bullet for physics |
| Roguelike / strategy | Heavy on Ashley, lighter on Scene2D |

### Generator Choice
| Need | Tool |
|------|------|
| New project (any size) | gdx-liftoff |
| Legacy projects pre-2023 | gdx-setup.jar (deprecated, avoid for new work) |

### Build System
| Concern | Recommendation |
|---------|---------------|
| Build tool | Gradle (only officially supported) |
| Gradle version | Match what gdx-liftoff generates (9.x as of 2025) |
| JDK build target | Java 21 (Java 17 minimum) |
| iOS source level | Capped at Java 8 by RoboVM constraint |

## Behavioral Rules

- Always recommend `gdx-liftoff` over `gdx-setup` for new projects
- Always check Kotlin compatibility with the target platform set (NO Kotlin if HTML5/GWT is required)
- Always require explicit `.dispose()` on every OpenGL resource (Texture, Sound, Music, Stage, Skin, Atlas, BitmapFont, ShaderProgram, ParticleEffect, FrameBuffer)
- Always forbid static AssetManager / static Texture references in Android-targeting code
- Always set `Gdx.input.setInputProcessor()` in Screen `show()`, never in the constructor
- Always pack sprites into power-of-two TextureAtlases via TexturePacker; never load loose Textures per sprite
- Always set `Group.isTransform = false` on Scene2D Groups that do not rotate or scale
- Always run IO and computation on a worker thread; use `Gdx.app.postRunnable` to push back to GL thread
- Always recommend fixed-timestep Box2D simulation decoupled from render rate
- Always cache `ComponentMapper` references; never call `ComponentMapper.getFor` per-frame
- Warn that AssetManager has known sluggish loading; recommend multiple `update()` calls per frame during loading screens
- Warn that libGDX 1.14.0 deprecated `Pools` in favor of `PoolManager`; migrate accordingly
- Warn that `JsonValue#get` is now case-sensitive in 1.14.0

## Common Patterns

### Minimal Game with Screen

```java
public class MyGame extends Game {
    public SpriteBatch batch;
    public AssetManager assets;

    @Override
    public void create() {
        batch = new SpriteBatch();
        assets = new AssetManager();
        setScreen(new MainMenuScreen(this));
    }

    @Override
    public void dispose() {
        batch.dispose();
        assets.dispose();
        if (getScreen() != null) getScreen().dispose();
    }
}
```

### Async Loading Screen

```java
public class LoadingScreen extends ScreenAdapter {
    private final MyGame game;

    public LoadingScreen(MyGame game) {
        this.game = game;
        game.assets.load("atlas/game.atlas", TextureAtlas.class);
        game.assets.load("ui/skin.json", Skin.class);
        game.assets.load("audio/music.ogg", Music.class);
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(0, 0, 0, 1);
        for (int i = 0; i < 4 && !game.assets.update(); i++) {
            // Pump the loader multiple times per frame for snappier progress
        }
        if (game.assets.isFinished()) {
            game.setScreen(new GameplayScreen(game));
        }
    }
}
```

### Safe Disposal of Screen

```java
public class GameplayScreen extends ScreenAdapter {
    private final Stage stage;
    private final InputMultiplexer input = new InputMultiplexer();

    public GameplayScreen() {
        stage = new Stage(new FitViewport(1280, 720));
        input.addProcessor(stage);
    }

    @Override
    public void show() {
        Gdx.input.setInputProcessor(input);
    }

    @Override
    public void hide() {
        Gdx.input.setInputProcessor(null);
    }

    @Override
    public void dispose() {
        stage.dispose();
    }
}
```

### Fixed-Timestep Box2D

```java
private static final float STEP = 1f / 60f;
private float accumulator = 0f;

public void update(float delta) {
    accumulator += Math.min(delta, 0.25f);
    while (accumulator >= STEP) {
        world.step(STEP, 6, 2);
        accumulator -= STEP;
    }
}
```

### Ashley ECS Setup

```java
public class MovementSystem extends IteratingSystem {
    private final ComponentMapper<Position> pm = ComponentMapper.getFor(Position.class);
    private final ComponentMapper<Velocity> vm = ComponentMapper.getFor(Velocity.class);

    public MovementSystem() {
        super(Family.all(Position.class, Velocity.class).get());
    }

    @Override
    protected void processEntity(Entity entity, float deltaTime) {
        Position p = pm.get(entity);
        Velocity v = vm.get(entity);
        p.x += v.dx * deltaTime;
        p.y += v.dy * deltaTime;
    }
}
```

## Synergies

- **java/kotlin language support**: pair with general Java/Kotlin best practices; libGDX itself ships idiomatic Java
- **mattpocock-skills:tdd** (upstream mattpocock/skills): GameTest/HeadlessApplication for unit-testing render-free logic; integration tests for systems
- **docker:multi-stage-dockerfile**: for headless server-side gameplay simulation or build CI containers
- For parallel Screen/ECS/asset implementation across multiple agents, the upstream agent-teams plugin (wshobson/agents) provides `/agent-teams:team-feature`.

## Source References

- Official site: https://libgdx.com/
- Wiki (canonical): https://libgdx.com/wiki/
- API Javadoc (canonical): https://javadoc.io/doc/com.badlogicgames.gdx/gdx/latest/index.html
- Main repo: https://github.com/libgdx/libgdx
- gdx-liftoff: https://github.com/libgdx/gdx-liftoff
- Release 1.14.0 notes: https://libgdx.com/news/2025/10/gdx-1-14-0
- Performance guide (community canonical): https://yairm210.medium.com/the-libgdx-performance-guide-1d068a84e181
- Screen manager library: https://github.com/crykn/libgdx-screenmanager


