Preview and interact with real ModularUI2 Java layouts without starting Minecraft. The previewer compiles a small Java project and runs the real ModularUI2 screen lifecycle in a local runtime. It can open the GUI in a clickable desktop window, rebuild that window as files change, or render a full-screen PNG with machine-readable layout data for automated inspection.
The normal workflow is deliberately small:
- copy or write
ModularPanelconstruction code; - add the textures used by that code;
- choose a workflow:
opento click and inspect the GUI manually;watchto keep an interactive window open while editing Java, textures, or configuration;renderto producepreview.png,bounds.json, and optional scripted interaction captures.
The preview project uses normal ModularUI2 classes and widget APIs. There is no second layout language to translate back into production code.
- Windows, Linux, or macOS;
- JDK 21;
- internet access on the first run so the Gradle Wrapper can download build dependencies.
Gradle does not need to be installed separately.
Download the ZIP on Windows or the tar.gz archive on Linux and macOS, extract it, and run preview.bat help or ./preview.sh help. Release archives already contain the compiled previewer and do not require Gradle. They still require JDK 21 because preview projects compile Java source code on every build.
The launchers use JAVA_HOME when it is set, otherwise they use java and javac from PATH. A JRE without javac is not sufficient.
Push a version tag to build and publish the release archives:
git tag v0.1.0
git push origin v0.1.0GitHub Actions verifies the project and attaches a versioned ZIP and tar.gz archive to the tag's release. Regular pushes and pull requests run verification without publishing a release.
The previewer uses the original Minecraft 1.7.10 font from the developer's
local client.jar; Minecraft assets are not included in this repository.
For a normal GTNH development setup no configuration is needed. The launcher
automatically checks:
%USERPROFILE%\.gradle\caches\retro_futura_gradle\mc-vanilla\1.7.10\client.jar
When GRADLE_USER_HOME is set, its cache is checked instead.
If the JAR is elsewhere, point the previewer at it before launching. In PowerShell:
$env:MODULARUI2_PREVIEW_MINECRAFT_JAR = "C:\path\to\client.jar"
.\preview.bat render examples\starter-panelIn Command Prompt:
set MODULARUI2_PREVIEW_MINECRAFT_JAR=C:\path\to\client.jar
preview.bat render examples\starter-panelOn Linux or macOS:
MODULARUI2_PREVIEW_MINECRAFT_JAR=/path/to/client.jar ./preview.sh render examples/starter-panelUse the Minecraft 1.7.10 client.jar downloaded or generated by
RetroFuturaGradle.
From the repository root, open the GT5 Basic Electrolyzer in an interactive desktop window:
preview.bat open examples\gt5-electrolyzer-directOn Linux or macOS:
./preview.sh open examples/gt5-electrolyzer-directThe example is a visual extraction of the production GT5 Basic Electrolyzer layout. Its textures are copied from the GT5 production assets used by the layout. Hover and click its local toggle buttons to verify pressed, hovered, and changed widget states. Interaction runs entirely inside the previewer; it does not simulate a Minecraft server or machine backend.
Use watch instead of open while editing the example. A successful rebuild replaces the displayed GUI. A compilation or render failure leaves the last working GUI visible and retries after the next file change:
preview.bat watch examples\gt5-electrolyzer-directUse render when you need artifacts for a screenshot comparison or an agent rather than a desktop window:
preview.bat render examples\gt5-electrolyzer-directFor a minimal project intended to be copied and edited, run:
preview.bat render examples\starter-panelThe result is written to:
output/StarterPanelPreview/preview.png
output/StarterPanelPreview/bounds.json
The first launch builds the local previewer distribution. Warm renders normally finish in one or two seconds.
Create a complete starter project:
preview.bat init my-machine-previewThe command creates this shape:
my-machine-preview/
preview.properties
src/
preview/
java/
example/
StarterPanelPreview.java
resources/
assets/
The generated preview.properties selects the Java entrypoint and the simulated monitor:
preview.entrypoint=example.StarterPanelPreview
screen.width=1920
screen.height=1080
gui.scale=auto
screen.background=#101820Edit src/preview/java/example/StarterPanelPreview.java and replace the starter panel with production-shaped layout code. Open it interactively with:
preview.bat open my-machine-previewSwitch to watch for continuous rebuilding, or use render when you need PNG and JSON artifacts. The previewer compiles every .java file below src/preview/java on each run.
Put preview-owned assets below:
src/preview/resources/assets/<domain>/<path>
For this production texture reference:
UITexture.fullImage("mymod", "textures/gui/machine.png")the corresponding file is:
src/preview/resources/assets/mymod/textures/gui/machine.png
The previewer also supplies the assets contained in its pinned ModularUI2 and ModularUI artifacts. A direct visual preview normally needs only the mod-specific textures used by the panel.
There are two supported project shapes.
Copy the production panel-building code into the preview entrypoint and remove machine logic that is irrelevant to drawing. Keep the real widget classes, positions, sizes, texture paths, and panel structure.
Use this mode for fast layout and appearance iteration. The included GT5 Electrolyzer is the reference example.
When the GUI builder can be loaded without starting Forge, point the preview project at the mod's compiled output with runtime-classpath.txt:
C:\work\MyMod\build\classes\java\main
C:\work\MyMod\build\resources\main
C:\path\to\a-production-dependency.jar
Use one directory or JAR per line. Empty lines and lines beginning with # are ignored. Relative entries are resolved from the preview project directory.
Do not add ModularUI2 or ModularUI to this file. The previewer supplies the pinned versions that match its headless runtime:
- ModularUI2
2.3.84-1.7.10; - ModularUI
1.3.4.
The entrypoint constructs representative state and calls the production builder:
public final class MyMachinePreview implements PreviewEntrypoint {
@Override
public Class<?> previewedClass() {
return MyMachineGui.class;
}
@Override
public Object createPanel(Context context) {
MyMachine machine = new MyMachine();
machine.setStoredEnergy(4_000);
return MyMachineGui.build(
machine,
(PanelSyncManager) context.panelSyncManager());
}
}previewedClass() records the production GUI class in bounds.json. This makes it possible to verify that the screenshot came from production code rather than a lookalike adapter.
The Galaxia Oxygen Filler under integrations/galaxia-oxygen-filler demonstrates this integration shape. It requires a compiled Galaxia checkout and its production dependencies in runtime-classpath.txt.
libs/contains ordinary project runtime JARs.extensions/contains previewer extension providers.assets/is an alternative asset root equivalent tosrc/preview/resources/assets/.runtime-classpath.txtcontains compiled production classes, resources, and dependencies.
The normal direct-panel project does not need any of these directories.
Open the configured panel in a desktop window:
preview.bat open project-directoryMouse hover, left and right button presses, releases, clicks, and wheel scrolling are sent to the real ModularUI2 screen. The panel stays alive until the window is closed, so local widget callbacks can change the next rendered frame. This mode does not simulate a Minecraft server or network-backed behavior.
For continuous layout work, watch the project instead:
preview.bat watch project-directoryThe previewer waits until changed Java, assets, configuration, or runtime inputs have remained stable for 300 milliseconds, then compiles a fresh UI session. A successful build replaces the displayed session and updates preview.png and bounds.json. A failed build leaves the last successful layout visible and marks it stale below the simulated monitor; the next file change retries automatically.
For repeatable agent-driven interaction, create a text file such as actions.txt:
# Coordinates use the full preview framebuffer.
move 960 540
click left
# Widget paths come from bounds.json, for example 0/3/1.
move-widget 0/3/1
scroll down 2
capture after-scroll
Run the full file in one live session:
preview.bat render project-directory --actions actions.txtAvailable commands are move x y, move-widget path, press left|right, release left|right, click left|right, scroll up|down [amount], and capture name. Each capture is written below output/<PreviewClass>/captures/<name>/ as preview.png, bounds.json, and actions.json. Invalid commands and missing widget paths report the source line.
Create a runnable starter:
preview.bat init project-directoryRender once using the entrypoint from preview.properties:
preview.bat render project-directoryOverride the entrypoint and output directory:
preview.bat render project-directory --class fully.qualified.PreviewClass --output output/my-iterationOpen an interactive window or show command help:
preview.bat open project-directory
preview.bat watch project-directory
preview.bat helpThe shell launcher accepts the same commands:
./preview.sh init project-directory
./preview.sh render project-directory [--class name] [--output directory] [--config file] [--actions file]
./preview.sh open project-directory [--class name] [--config file]
./preview.sh watch project-directory [--class name] [--output directory] [--config file]
./preview.sh helpEvery successful render produces:
preview.png: the entire simulated monitor, not a cropped panel;bounds.json: framebuffer size, GUI scale, panel bounds, widget bounds, provenance, consumed assets, warnings, and completion status.
A healthy render has:
statusequal tocomplete;- the expected
previewedClassandpanelCodeSource; - the expected mod texture paths in
assets; - an empty
warningsarray.
The runtime executes real ModularPanel, ModularScreen, ModularContainer, sync collection, player-slot binding, widget initialization, layout, update, and draw calls.
The production acceptance surface covers rectangles, text, ModularUI2 textures, progress bars, empty item slots, player inventory, and full-screen GUI scaling.
The headless Minecraft/OpenGL boundary is intentionally smaller than the game. Entity rendering, non-empty item-stack icons, custom shaders or framebuffers, and mod-specific direct OpenGL code are not complete. Keyboard input, text entry, drag-and-drop, animation ticks, hot reload, and server/network simulation are not part of the local interaction host. A reachable missing ABI is a previewer implementation gap; do not replace production GUI code with an invented lookalike to hide it.
Add the fully qualified preview class to preview.properties:
preview.entrypoint=example.MyMachinePreviewThe package declaration, directory structure, and configured class name must agree.
Build the mod, then add its class directory, resource directory, and required production dependencies to runtime-classpath.txt.
For quick visual iteration, use a direct panel preview and remove machine lifecycle code that is not needed to construct the panel.
Check the exact domain and path passed to UITexture, then place the PNG under the matching assets/<domain>/... path. Inspect the assets array in bounds.json to confirm which file was consumed.
gui.scale=auto uses Minecraft's scale calculation for the configured framebuffer. Set an explicit value such as gui.scale=2 while diagnosing unusually large layouts.
Run the complete verification suite:
gradlew.bat agentVerify./gradlew agentVerifyThe suite compiles the runtime, runs its tests, and renders the bundled GT5 example without an external classpath.
ModularUI2 Preview is licensed under LGPL-3.0-only. Third-party components and
the GT5 example are listed in THIRD_PARTY_NOTICES.md.