A Minecraft Fabric mod that splits screenshots into multiple layers so you can retroactively hide the GUI or hot bar from view in your screenshots.
Looking back at my Minecraft screenshots, I sometimes wish I had taken them in F1
mode so the hotbar would be hidden.
This lead me to sometimes take two screenshots, one with the GUI showing and one with it hidden, there had to be a better way.
I searched around a bit and was surprised and kinda happy to see that nothing to solve this already existed, which meant that I had the rare opportunity to make something new and potentially useful.
Download Links
At the time of writing Modrinth has still not approved the mod 🙄
The mod is available for download on Modrinth, Github, and Curse Forge. (In order of preference)
Usage
Once installed, a new keybind will be added to the controls menu. You may want to unbind the default take screenshot key and bind F2 to Screenshot Layer’s capture binding. Screenshot Layers outputs .tiff files, as it’s one of the few mainstream image formats that supports multiple layers. If you open one of these files in Photoshop, PhotoPea, GIMP, or another image editor, you can view and modify the individual layers separately.
Screenshot of a layered screenshot open in GIMP. See the layer panel on the right showing the 5 layers in this screenshot.
Layers
Not every layer will be added to every screenshot, only the ones that are diffrent from the others. For example the overlay layer will only show if the player has some overlay from a carved pumpkin, power snow, or a potion. Optional layers are denoted with an asterisk.
World | Player Hand* | Overlays* |
---|---|---|
Hotbar | In Game HUD | Screen* |
How it Works
I used Mixins to inject some code at a few key-points during Minecraft’s rendering pipeline to asynchronously download the framebuffer. See this excerpt from GameRendererMixin.java for example:
@Inject(method = "renderWorld", at = @At("TAIL"))
void onRenderWorldTail(CallbackInfo ci) {
if (builder == null || !builder.layers.hand) return;
ScreenshotLayers.screenshotLayer("Player Hand", 1);
}
The screenshotLayer
function in ScreenshotLayers.java just calls Minecraft’s built-in takeScreenshot
method, which runs the specified callback once the framebuffer is downloaded.
public static void screenshotLayer(String name, int n) {
if (builder == null) return;
takeScreenshot(client.getFramebuffer(), image -> {
if (ScreenshotLayers.builder == null) return;
var layer = new ScreenshotBuilder.ScreenshotLayer(image, name);
ScreenshotLayers.builder.pushLayer(layer, n);
});
}
Once the builder is supplied with all of the expected layers, it uses Tiff Java to write a .tiff file with each of the named layers.
The hardest part was getting images during the GUI rendering process, because by default as the GUI is built all the draw calls are queued and then dispatched at the end.
This means that if you were to just call screenshotLayer
during this process, you would just get a bunch of layers showing the world with no GUI, then the last layer would show all the GUI layers.
The obvious way to fix this is to just dispatch all the queued draw calls each time you download the framebuffer, but when I tried that, I got some interesting results…
public static void renderGui() {
var guiRenderer = client.gameRenderer.guiRenderer;
// ↓ just ignore this
var fog = client.gameRenderer.fogRenderer;
var emptyBuffer = fog.getFogBuffer(FogRenderer.FogType.NONE);
guiRenderer.render(emptyBuffer);
}
For some reason the layering was all wrong, and I don’t even know what’s going on with the blur in the right one. I spent like an hour fiddling with stuff trying to figure out what was going on here, but eventually realized I just needed to clear the depth buffer after each early dispatch of draw calls.
var encoder = RenderSystem.getDevice().createCommandEncoder();
var depthBuffer = client.getFramebuffer().getDepthAttachment();
encoder.clearDepthTexture(depthBuffer, 1.0);
Future Ideas
At some point I want to integrate some kinda config menu so you can select which layers you want to be saved, if you don’t always want them all. Also because the .tiff files can get really big, ~35MiB at high resolutions with all layers showing, I want to look into other formats with better compression, lossless or lossy, to make this a more practical utility for replacing the default screenshot function.