| name | fxgl-intelligence |
| description | Integrate ML-powered intelligence features into an FXGL game via the fxgl-intelligence module — face detection from webcam, hand gesture recognition, hand landmark tracking, speech recognition for voice commands, and platform text-to-speech. Use this skill when building accessibility features, gesture-controlled games, voice-commanded gameplay, facial-expression-driven mechanics, or spoken NPC dialogue.
|
| triggers | ["face detection","gesture recognition","speech recognition","voice command","hand tracking","text to speech","TTS","webcam","ML","fxgl-intelligence","facial expression","hand gesture"] |
| compatibility | Java 17+, FXGL 21.x, fxgl-intelligence module. Requires Python ML backend running locally (see references/ml-backend-setup.md). TTS requires platform speech engine (SAPI/NSS/espeak).
|
| category | fxgl/intelligence |
| tags | ["fxgl","java","javafx","intelligence"] |
| metadata | {"author":"fxgl-skills","version":"1.0","fxgl-version":"21.1"} |
| allowed-tools | ["Read","Write","Edit","Bash"] |
FXGL Intelligence Module
Dependency Setup
Add to pom.xml (replace VERSION with current FXGL version):
<dependency>
<groupId>com.github.almasb</groupId>
<artifactId>fxgl-intelligence</artifactId>
<version>VERSION</version>
</dependency>
The intelligence module communicates with a local Python ML service via WebSocket on
configurable ports. See references/ml-backend-setup.md
for how to install and run the Python service.
Face Detection
Detects faces via webcam and provides bounding box + landmark positions.
settings.addEngineService(FaceDetectService.class);
FaceDetectService faceDetect = getService(FaceDetectService.class);
faceDetect.setOnFaceDetected(faceData -> {
double faceX = faceData.getBounds().getMinX();
double faceY = faceData.getBounds().getMinY();
getGameScene().getViewport().setX(faceX * getAppWidth());
});
faceDetect.setOnFaceLost(() -> {
System.out.println("No face detected — pause game?");
getGameController().pauseEngine();
});
faceDetect.start(0);
Gesture Recognition
Recognises predefined hand gestures from webcam frames.
settings.addEngineService(GestureRecognitionService.class);
GestureRecognitionService gestures = getService(GestureRecognitionService.class);
gestures.setOnGestureRecognised(gesture -> {
switch (gesture) {
case THUMBS_UP -> jump();
case FIST -> punch();
case OPEN_HAND -> shield();
case PEACE -> specialMove();
case POINTING -> aimAtPoint(getInput().getMousePositionWorld());
case THUMBS_DOWN -> decreaseVolume();
}
});
gestures.start(0);
Available Gestures
| Gesture | Value | Typical use |
|---|
THUMBS_UP | Fist + thumb up | Confirm / jump |
THUMBS_DOWN | Fist + thumb down | Reject / crouch |
FIST | All fingers closed | Attack / dash |
OPEN_HAND | All fingers extended | Pause / shield |
PEACE | Index + middle extended | Special move |
POINTING | Only index extended | Aim / select |
Hand Tracking (Landmarks)
Provides 21 landmark positions for each detected hand (sub-pixel accuracy).
settings.addEngineService(HandTrackingService.class);
HandTrackingService handTrack = getService(HandTrackingService.class);
handTrack.setOnHandLandmarks(landmarks -> {
HandLandmark wrist = landmarks.get(HandLandmark.WRIST);
HandLandmark indexTip = landmarks.get(HandLandmark.INDEX_FINGER_TIP);
HandLandmark thumbTip = landmarks.get(HandLandmark.THUMB_TIP);
double screenX = indexTip.getX() * getAppWidth();
double screenY = indexTip.getY() * getAppHeight();
getInput().mockCursorPosition(screenX, screenY);
double pinchDist = thumbTip.distanceTo(indexTip);
if (pinchDist < 0.05) {
getInput().mockButtonPress(MouseButton.PRIMARY);
}
});
handTrack.start(0);
Hand Landmark Constants
HandLandmark.WRIST
HandLandmark.THUMB_CMC
HandLandmark.THUMB_TIP
HandLandmark.INDEX_FINGER_MCP
HandLandmark.INDEX_FINGER_TIP
HandLandmark.MIDDLE_FINGER_TIP
HandLandmark.RING_FINGER_TIP
HandLandmark.PINKY_TIP
Speech Recognition (Voice Commands)
Transcribes spoken audio and returns recognised text.
settings.addEngineService(SpeechRecognitionService.class);
SpeechRecognitionService speech = getService(SpeechRecognitionService.class);
speech.setLanguage("en-US");
speech.setModel("base");
speech.setOnSpeechRecognised(text -> {
String cmd = text.toLowerCase().trim();
if (cmd.contains("jump")) jump();
else if (cmd.contains("attack")) attack();
else if (cmd.contains("pause")) getGameController().pauseEngine();
else if (cmd.contains("help")) showHelpOverlay();
else pushNotification("Unknown command: " + cmd);
});
speech.start();
speech.stop();
Text-to-Speech (Platform Native)
settings.addEngineService(TextToSpeechService.class);
TextToSpeechService tts = getService(TextToSpeechService.class);
tts.setLanguage(Locale.ENGLISH);
tts.setRate(1.0);
tts.setPitch(1.0);
tts.setVolume(1.0);
tts.speak("Welcome to the dungeon!");
tts.speakAndWait("Are you sure you want to quit?");
getCutsceneService().startCutscene(scene, () -> {
tts.speak("The adventure continues...");
});
Graceful Fallback When Backend Unavailable
FaceDetectService fds = getService(FaceDetectService.class);
fds.setOnError(e -> {
System.err.println("Face detection unavailable: " + e.getMessage());
showMessage("Camera unavailable. Using keyboard controls.");
});
if (fds.isAvailable()) {
fds.start(0);
} else {
}
Gotchas
- Python backend must be running before the FXGL app starts the intelligence services.
The services connect via WebSocket on startup and fail silently if the backend is offline.
See references/ml-backend-setup.md.
speak() is non-blocking — speech plays asynchronously. If you need sequential speech
(line 1 then line 2), use speakAndWait() or chain via callbacks.
- Gesture recognition requires well-lit environment — poor lighting causes low confidence
scores and missed gestures. Communicate lighting requirements to players.
HandLandmark.get(index) uses integer indices 0-20; use the enum constants for
readability — they are integer constants, not enum objects.
- Speech recognition latency varies with model size: "tiny" ≈ 100ms, "large" ≈ 2s on
CPU. Use "tiny" or "base" for real-time voice commands.
- Platform TTS quality varies: Windows SAPI is high quality; Linux espeak is robotic.
Test on target platform.
- Camera access requires OS permission — on macOS and recent Windows, a camera
permission dialog appears on first access. Handle denial gracefully.