How fx2048 is built and packaged.
fx2048 is a small modular Java app with a JavaFX UI, a custom desktop runtime image, native installers, optional JPro browser deployment, and a deliberately tight runtime footprint. Its recent modernization was planned, implemented, debugged, and documented with GitHub Copilot.
Project at a glance
Current source and runtime facts from the repository and latest published release.
Built with GitHub Copilot
GitHub Copilot helped drive the current version of fx2048 end to end, from gameplay polish to signed releases and this website.
Game and UI improvements
Copilot helped iterate on the desktop experience, including controls, overlays, status information, layout fixes, and visual refinements.
Release automation
Copilot assisted with Maven, GitHub Actions, jlink, jpackage, platform artifacts, version bumps, changelog updates, and release workflow fixes.
macOS signing diagnostics
Copilot helped diagnose and fix hardened runtime, JVM JIT, JavaFX native library validation, DMG signing, notarization, and Gatekeeper issues.
Documentation and agent skills
Copilot authored the GitHub Pages site and captured the macOS JavaFX signing lessons as a reusable agent skill for future projects.
Technology stack
The app is intentionally simple: Java modules, JavaFX controls and animation APIs, Maven automation, platform-native packages, and an optional JPro browser runtime.
Application runtime
Java 25, JavaFX 25.0.3, and the JPMS module fxgame. The launcher enters io.fxgame.game2048.AppLauncher.
UI and animation
JavaFX scene graph, CSS styling, keyboard and swipe input, tile move/merge animations, overlays, score effects, and a lightweight status bar.
Game model
The game rules live in Java classes for grid traversal, tile state, move/merge flow, scoring, game-over checks, persistence, and records.
Build and packaging
Maven builds the app, jlink creates a custom runtime, and jpackage produces DMG, MSI, and DEB installers.
Browser deployment
JPro can run the JavaFX application on a server and stream the UI to a browser, using a separate Maven profile from the desktop packaging path.
Libraries and tools
The dependency list is short, which keeps the desktop app easy to audit and package.
| Category | Technology |
|---|---|
| Language and UI framework |
Java 25 with JavaFX 25.0.3 modules: javafx-base, javafx-graphics, and javafx-controls.
JavaFX source lives in the OpenJDK jfx repository, while JavaFX binaries are published by Gluon at openjfx.io.
|
| Tests | JUnit Jupiter 5.11.4 through Maven Surefire 3.5.3. |
| Build | Maven wrapper, Maven Compiler Plugin 3.15.0, JavaFX Maven Plugin 0.0.8, Maven JAR Plugin 3.5.0, jpackage Maven Plugin 1.7.4, and JPro Maven Plugin 2026.1.1. |
| Packaging | jlink strips the runtime image, and jpackage creates native installers from that runtime. |
| Browser runtime | JPro serves the JavaFX application over HTTP from the Maven jpro profile, with platform profiles selecting JPro-compatible JavaFX native artifacts. |
JPro browser deployment model
JPro is a separate runtime path for trying the JavaFX game in a browser without rewriting the UI in HTML and JavaScript.
Server-side JavaFX
The JavaFX application runs in a JVM on the server. JPro exposes it at http://localhost:8080/index.html during local development and streams the UI to the browser.
Different entry point
The desktop launcher uses io.fxgame.game2048.AppLauncher, but JPro is configured with io.fxgame.game2048.Game2048 because JPro needs the class that directly extends javafx.application.Application.
Maven profiles
Run JPro with the shared jpro profile plus one platform profile: jpro-macos-aarch64, jpro-linux-amd64, or jpro-linux-aarch64. Windows is not part of this JPro setup.
Lifecycle
jpro:run starts an attached development server. jpro:restart starts a background server and writes its process id to RUNNING_PID.
Runtime profile
fx2048 is tuned for a small desktop-game footprint rather than server-style throughput.
| Setting or behavior | Value |
|---|---|
| Java heap | -Xms8m, -Xmx32m, -XX:MinHeapFreeRatio=10, and -XX:MaxHeapFreeRatio=20 |
| Garbage collector | -XX:+UseG1GC with -XX:G1PeriodicGCInterval=10000 and -XX:+G1PeriodicGCInvokesConcurrent |
| Native footprint limits | -Xss512k thread stacks, -XX:ReservedCodeCacheSize=12m, -XX:CICompilerCount=2, and -XX:TieredStopAtLevel=1. |
| Status bar | Shows live CPU, memory, and garbage-collection count while the game is running. |
| Persistence | Saves local settings, session state, elapsed time, score, and best-score records under the user's home directory. |
Memory use across 2048 implementations
A 2048 board is tiny; most memory comes from the runtime that hosts it. These local snapshots compare three ways to ship the same kind of game.
Takeaway
fx2048's packaged JavaFX build measured about 189 MB on macOS: larger than a small Cocoa/WebKit wrapper, but lower than the same kind of game running inside a full Chrome tab.
The 32 MB Java heap cap is a JVM tuning boundary, not total process memory. Native runtime, graphics, code cache, stacks, and libraries sit outside the heap.
| Implementation | Observed memory | Runtime | What it means |
|---|---|---|---|
| fx2048 packaged app | ~189 MB physical footprint | JavaFX app with a custom jlink runtime and tuned JVM options. | A focused desktop JVM profile, including more than just the Java heap. |
| 2048 Game.app | ~117 MiB RSS | Cocoa/AppKit shell with WebKit hosting bundled HTML, CSS, and JavaScript assets. | A compact WebKit wrapper, not Electron, Java, Node, or a fully custom native renderer. |
| play2048.co in Chrome | 282 MB | The JavaScript game hosted inside a full Chrome browser tab. | The largest baseline here because the full browser runtime comes with the tab. |
Runtime footprint snapshot
The chart is normalized to the Chrome tab's 282 MB measurement. RSS, physical footprint, and Chrome Task Manager are different measurements, so treat this as a practical comparison rather than a lab benchmark. The 32 MB Java heap cap is not plotted because it is a tuning limit, not process memory.
Code and package size
The page keeps the source stats static and reads current release package sizes from GitHub when available.
| Main Java | 2,468 lines across 21 files |
| Tests | 223 Java lines across 3 files |
| Styling | 392 lines of JavaFX CSS |
| Tracked source/config total | 3,084 lines |
| Latest release packages | Loading package sizes... |
Release pipeline
GitHub Actions builds platform installers and publishes signed releases.
macOS
Builds an Apple Silicon DMG, signs the app with hardened runtime entitlements, signs the disk image, notarizes it with Apple, staples it, and validates Gatekeeper.
Windows and Linux
Builds a Windows x64 MSI and Linux amd64/arm64 DEB packages, each bundling the custom runtime needed by the game.