Use FXGL's built-in developer tools during development — enable the developer menu (F1 overlay), inspect all active entities and their components at runtime, use the in-game console to run commands without recompiling, profile FPS and memory with the profiler window, visualise entity bounding boxes and collision shapes, switch application mode between DEVELOPER and RELEASE, register custom dev console commands via DevService, use FXGL.debug() for console logging, and visualise graphs (pathfinding, dialogue, quest) at runtime. Use this skill when debugging game behaviour, tuning AI, stress-testing level generation, inspecting entity state at runtime, or setting up a cheat/test console for development.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Use FXGL's built-in developer tools during development — enable the developer menu (F1 overlay), inspect all active entities and their components at runtime, use the in-game console to run commands without recompiling, profile FPS and memory with the profiler window, visualise entity bounding boxes and collision shapes, switch application mode between DEVELOPER and RELEASE, register custom dev console commands via DevService, use FXGL.debug() for console logging, and visualise graphs (pathfinding, dialogue, quest) at runtime. Use this skill when debugging game behaviour, tuning AI, stress-testing level generation, inspecting entity state at runtime, or setting up a cheat/test console for development.
@OverrideprotectedvoidinitSettings(GameSettings settings) {
settings.setWidth(1280);
settings.setHeight(720);
// Show developer pane on F1 (hidden in RELEASE mode automatically)
settings.setDeveloperMenuEnabled(true);
// Show FPS / memory / entity count / physics step duration overlay
settings.setProfilingEnabled(true);
// Application mode controls all dev features at once
settings.setApplicationMode(ApplicationMode.DEVELOPER);
// Use ApplicationMode.RELEASE for distribution (disables all dev overlays)
}
Application Modes
Mode
Dev Menu
Profiler
Logging
Exception Handling
DEVELOPER
enabled
enabled
verbose
crash with stack trace
DEBUG
enabled
enabled
verbose
crash with stack trace
RELEASE
hidden
hidden
minimal
graceful fallback
// Check mode at runtime to conditionally run dev codeif (getSettings().getApplicationMode() != ApplicationMode.RELEASE) {
// Only runs in DEVELOPER / DEBUG
registerDevCommands();
}
Developer Pane (F1 Overlay)
The dev pane opens by pressing F1 (when setDeveloperMenuEnabled(true)). It shows:
World Properties — all game variables, editable in real time
Entity list — all active entities; click to inspect components
Physics debug toggle — draws bounding boxes over all collidable entities
// Available anywhere in your game code// Appears in the dev console log and is suppressed in RELEASE mode
FXGL.debug("Player position: " + player.getPosition());
FXGL.debug("Enemy count: " + getGameWorld().getEntitiesByType(EntityType.ENEMY).size());
// Also works as a static import
debug("AStarGrid recalculated in " + elapsed + "ms");
Profiler Window
Enabled by settings.setProfilingEnabled(true). Displays:
// Toggle in dev pane, or enable programmatically:
getPhysicsWorld().setShowBoundingBoxes(true);
// Colors used:// DYNAMIC bodies → green box// STATIC bodies → blue box// SENSOR bodies → yellow box (triggers)// Visualise a single entity's bounding boxes
entity.getBoundingBoxComponent().visualise();
// Shows red outline around each hitbox of that entity only
Entity Inspector (Runtime Component View)
Click any entity in the dev pane entity list to open the EntityInspector:
Lists all attached components with their class names
Shows field values (primitives only — no deep graph)
Updates live every frame
// Make component data visible in the inspector: use simple fields.// The inspector uses reflection — public or package-private fields show automatically.// Wrap mutable state in fields (not anonymous lambdas) for visibility.publicclassSpeedComponentextendsComponent {
publicdoublespeed=150; // visible in inspectorpublicbooleanisSprinting=false;
// ...
}
Custom Dev Buttons in Dev Pane
// Add buttons that appear in the developer pane@OverrideprotectedvoidinitGame() {
getDevService().addButton("Teleport to Boss", () -> {
player.setPosition(bossRoom.getCenterX() * 32, bossRoom.getCenterY() * 32);
});
getDevService().addButton("Kill All Enemies", () -> {
getGameWorld().getEntitiesByType(EntityType.ENEMY)
.forEach(Entity::removeFromWorld);
});
getDevService().addButton("Max Stats", () -> {
set("gold", 9999);
set("health", 100);
set("ammo", 999);
});
}
Debug Camera
The dev pane includes a "Debug Camera" mode that decouples the view from the game camera:
Drag with middle mouse button to pan
Scroll wheel to zoom in and out
Press Esc to return to the game camera
Activated via the dev pane button — no code required.
Graph Visualisation
// Visualise node-edge graphs (pathfinding, dialogue trees, quest deps, etc.)import com.almasb.fxgl.dev.GraphVisualisation;
GraphVisualisationvis=newGraphVisualisation();
// Add nodes with positions
vis.addNode("Start", 100, 100);
vis.addNode("Room1", 300, 100);
vis.addNode("Room2", 300, 300);
vis.addNode("Boss", 500, 200);
// Add edges
vis.addEdge("Start", "Room1");
vis.addEdge("Start", "Room2");
vis.addEdge("Room1", "Boss");
vis.addEdge("Room2", "Boss");
// Render in the game scene (as a HUD overlay)
addUINode(vis.getView(), 0, 0);
// Remove when done
removeUINode(vis.getView());
Conditional Dev-Only Code Pattern
// Guard dev-only features so they are compiled out or skipped in RELEASEprivatevoidregisterDevCommands() {
if (getSettings().getApplicationMode() == ApplicationMode.RELEASE) return;
getDevService().registerCommand("noclip", args -> {
PhysicsComponentpc= player.getComponent(PhysicsComponent.class);
pc.setBodyType(pc.getBodyType() == BodyType.DYNAMIC
? BodyType.KINEMATIC
: BodyType.DYNAMIC);
});
getDevService().registerCommand("timescale", args -> {
doublescale= args.isEmpty() ? 1.0 : Double.parseDouble(args.get(0));
getGameWorld().getEntities().forEach(e -> {
if (e.hasComponent(EffectComponent.class)) {
e.getComponent(EffectComponent.class)
.startEffect(newSlowTimeEffect(Duration.seconds(60)));
}
});
});
}
Gotchas
Dev menu is hidden in RELEASE mode automatically — you do not need to remove dev code
before distribution. setApplicationMode(ApplicationMode.RELEASE) suppresses all dev overlays.
getDevService() is null if setDeveloperMenuEnabled(false) — always guard with
getSettings().getApplicationMode() != ApplicationMode.RELEASE before calling it.
settings.setProfilingEnabled(true) has a small FPS cost — the profiler samples every
frame. Disable it for final release builds or when benchmarking performance.
FXGL.debug() writes to stdout and the console log — it does NOT appear as an in-game
notification. Use pushNotification() for player-visible messages.
Entity inspector uses reflection — private fields with no public getter are not shown.
Make fields package-private or public on components you want to inspect.
getPhysicsWorld().setShowBoundingBoxes(true) is a global toggle — it affects all
entities. Toggling it rapidly can cause a frame of missing visuals due to scene graph update timing.
Graph visualisation is for debugging only — GraphVisualisation adds JavaFX nodes
directly; it is not backed by FXGL's entity system and won't appear in entity queries.
Debug camera breaks gameplay — while the debug camera is active, the game loop still runs
(enemies still move, timers tick). Use getGameController().pauseEngine() alongside the debug
camera if you need to freeze the world.