From a7ad4586274f34354d025e77aca7b7d24972a1ba Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 28 Sep 2026 19:20:33 +0200 Subject: [PATCH] Move the title screen's extras to its corners and dock The account chip and a quit button go in the top corners and the version in the bottom left, now smaller and fainter. Minecraft's options and Saturn's settings take the HUD editor's place in the dock, and the intro brings the menus and edges in after the logo. Faded elements now start hidden instead of at 10% opacity. Co-Authored-By: Claude Opus 5.5 --- .../org/saturnclient/ui/ElementRenderer.java | 5 ++ .../java/org/saturnclient/ui/anim/Fade.java | 4 +- .../ui/elements/AnimationStagger.java | 12 +++- .../saturnclient/ui/screens/TitleMenu.java | 71 +++++++++++-------- 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/saturnclient/ui/ElementRenderer.java b/src/main/java/org/saturnclient/ui/ElementRenderer.java index ec2cd96..c863d6c 100644 --- a/src/main/java/org/saturnclient/ui/ElementRenderer.java +++ b/src/main/java/org/saturnclient/ui/ElementRenderer.java @@ -26,6 +26,11 @@ public class ElementRenderer { for (Element element : elements) { element.playAnimationFrame(elapsed); + // Not faded in yet + if (element.opacity <= 0) { + continue; + } + renderScope.getMatrixStack().push(); renderScope.setOpacity(element.opacity); renderScope.getMatrixStack().translate(element.x, element.y); diff --git a/src/main/java/org/saturnclient/ui/anim/Fade.java b/src/main/java/org/saturnclient/ui/anim/Fade.java index 9a5ecef..9663e42 100644 --- a/src/main/java/org/saturnclient/ui/anim/Fade.java +++ b/src/main/java/org/saturnclient/ui/anim/Fade.java @@ -16,12 +16,12 @@ public class Fade extends Animation { @Override public void tick(double progress, Element element) { - element.opacity = Math.max(0.1f, targetOpacity * (float) progress); + element.opacity = targetOpacity * (float) progress; } @Override public void init(Element element) { targetOpacity = element.opacity; - element.opacity = 0.1f; + element.opacity = 0; } } diff --git a/src/main/java/org/saturnclient/ui/elements/AnimationStagger.java b/src/main/java/org/saturnclient/ui/elements/AnimationStagger.java index 80dba99..c27c897 100644 --- a/src/main/java/org/saturnclient/ui/elements/AnimationStagger.java +++ b/src/main/java/org/saturnclient/ui/elements/AnimationStagger.java @@ -13,6 +13,8 @@ import org.saturnclient.ui.RenderScope; public class AnimationStagger extends Element { protected List children = new ArrayList<>(); public int delay; + /** When the first child starts, in ms */ + public int start = 0; public AnimationStagger(int delay) { this.delay = delay; @@ -22,13 +24,21 @@ public class AnimationStagger extends Element { this.delay = config.stagger.value; } + /** + * Holds the children back until {@code start} ms after the screen opens. + */ + public AnimationStagger after(int start) { + this.start = start; + return this; + } + public void draw(Element element) { if (!Config.stagger.value) { element.animation = null; } if (element.animation != null) { - element.animation.delay = delay * children.size(); + element.animation.delay = start + delay * children.size(); } ElementRenderer.draw(children, element); diff --git a/src/main/java/org/saturnclient/ui/screens/TitleMenu.java b/src/main/java/org/saturnclient/ui/screens/TitleMenu.java index 6d7e040..86b4caf 100644 --- a/src/main/java/org/saturnclient/ui/screens/TitleMenu.java +++ b/src/main/java/org/saturnclient/ui/screens/TitleMenu.java @@ -10,6 +10,7 @@ import org.saturnclient.config.property.FloatProperty; import org.saturnclient.config.Theme; import org.saturnclient.ui.Element; import org.saturnclient.ui.SaturnScreen; +import org.saturnclient.ui.anim.Animation; import org.saturnclient.ui.anim.Fade; import org.saturnclient.ui.anim.SlideFade; import org.saturnclient.ui.anim.SlideY; @@ -17,14 +18,16 @@ import org.saturnclient.ui.components.AccountChip; import org.saturnclient.ui.components.Dock; import org.saturnclient.ui.elements.AnimationStagger; import org.saturnclient.ui.elements.Button; +import org.saturnclient.ui.elements.IconButton; import org.saturnclient.ui.elements.ImageTexture; import org.saturnclient.ui.elements.Label; import org.saturnclient.ui.resources.Fonts; import org.saturnclient.ui.resources.Textures; /** - * Saturn's title screen: the logo over the game's menus in the middle, and - * along the bottom the player, a dock of Saturn's screens and the version. + * Saturn's title screen: the logo over the game's menus in the middle, the + * player and a quit button in the top corners, and along the bottom a dock of + * Saturn's screens and Minecraft's options, and the version. */ public class TitleMenu extends SaturnScreen { // The logo and wordmark as the shift menu has them: the wordmark over the logo's foot @@ -37,8 +40,16 @@ public class TitleMenu extends SaturnScreen { private static final int COLUMN_WIDTH = 280; private static final int BUTTON_HEIGHT = 36; private static final int GAP = 8; - private static final int EDGE = 28; - private static final float VERSION_SCALE = 0.62f; + /** Space around the account chip, quit button, dock and version, from the screen's edges */ + private static final int EDGE = 14; + private static final int QUIT_SIZE = 32; + + // The intro, in ms: the logo, then the menus, then what's around the edges + private static final int MENUS_DELAY = 250; + private static final int EDGES_DELAY = 450; + private static final int EDGES_STAGGER = 60; + private static final float VERSION_SCALE = 0.5f; + private static final float VERSION_ALPHA = 0.6f; public TitleMenu() { super("Title Menu"); @@ -54,7 +65,7 @@ public class TitleMenu extends SaturnScreen { blurBackground = false; // Logo and menus, centered together a little above the middle - int menusHeight = BUTTON_HEIGHT * 3 + GAP * 2; + int menusHeight = BUTTON_HEIGHT * 2 + GAP; int blockHeight = LOGO + MENUS_GAP + menusHeight; int top = (height - blockHeight) / 2 - 20; @@ -67,57 +78,57 @@ public class TitleMenu extends SaturnScreen { .position((width - WORDMARK_WIDTH) / 2, top + WORDMARK_Y) .animation(new Fade(AnimationConfig.logo.duration.value))); - int rowHeight = BUTTON_HEIGHT + GAP; - int halfWidth = (COLUMN_WIDTH - GAP) / 2; - AnimationStagger menus = new AnimationStagger(AnimationConfig.mainMenu); + AnimationStagger menus = new AnimationStagger(AnimationConfig.mainMenu).after(MENUS_DELAY); addMenuButton(menus, new Button("Singleplayer", () -> Providers.saturn.getClient().setScreen(MinecraftScreen.SelectWorld)) .dimensions(COLUMN_WIDTH, BUTTON_HEIGHT).position(0, 0)); addMenuButton(menus, new Button("Multiplayer", () -> Providers.saturn.getClient().setScreen(MinecraftScreen.Multiplayer)) - .dimensions(COLUMN_WIDTH, BUTTON_HEIGHT).position(0, rowHeight)); - addMenuButton(menus, new Button("Options", - () -> Providers.saturn.getClient().setScreen(MinecraftScreen.Options)) - .dimensions(halfWidth, BUTTON_HEIGHT).position(0, rowHeight * 2)); - addMenuButton(menus, new Button("Quit", - () -> Providers.saturn.getClient().scheduleStop()) - .dimensions(halfWidth, BUTTON_HEIGHT).position(COLUMN_WIDTH - halfWidth, rowHeight * 2)); + .dimensions(COLUMN_WIDTH, BUTTON_HEIGHT).position(0, BUTTON_HEIGHT + GAP)); draw(menus.position((width - COLUMN_WIDTH) / 2, top + LOGO + MENUS_GAP)); - // Along the bottom: the player, Saturn's screens, the version + // Top corners: the player, and quitting the game draw(new AccountChip() - .position(EDGE, height - EDGE - AccountChip.HEIGHT) - .animation(new Fade(AnimationConfig.mainMenu))); + .position(EDGE, EDGE) + .animation(delayed(new SlideFade(AnimationConfig.mainMenu, 8), EDGES_DELAY))); + draw(new IconButton(Textures.ICON_CLOSE, () -> Providers.saturn.getClient().scheduleStop()) + .dimensions(QUIT_SIZE, QUIT_SIZE) + .position(width - EDGE - QUIT_SIZE, EDGE + (AccountChip.HEIGHT - QUIT_SIZE) / 2) + .animation(delayed(new SlideFade(AnimationConfig.mainMenu, 8), EDGES_DELAY))); + // Along the bottom: the dock of Saturn's screens and Minecraft's options, and the version Dock dock = new Dock(List.of( new Dock.Item(Textures.ICON_MODS, () -> Providers.saturn.getClient().setScreen(new ModMenu())), new Dock.Item(Textures.ICON_COSMETICS, () -> Providers.saturn.getClient().setScreen(new CosmeticsMenu())), - new Dock.Item(Textures.ICON_HUD_EDITOR, - () -> Providers.saturn.getClient().setScreen(new HudEditor())), + new Dock.Item(Textures.LOGO, () -> Providers.saturn.getClient().setScreen(new ClientSettings())), new Dock.Item(Textures.ICON_SETTINGS, - () -> Providers.saturn.getClient().setScreen(new ClientSettings())))); + () -> Providers.saturn.getClient().setScreen(MinecraftScreen.Options)))); draw(dock.position((width - dock.width) / 2, height - EDGE - Dock.HEIGHT) - .animation(new SlideFade(AnimationConfig.mainMenu, 12))); + .animation(delayed(new SlideFade(AnimationConfig.mainMenu, -12), EDGES_DELAY + EDGES_STAGGER))); String version = getVersionText(); - int versionWidth = (int) (Fonts.getWidth(version, Theme.getBodyFont()) * VERSION_SCALE); int versionHeight = (int) (Fonts.getHeight() * VERSION_SCALE); - draw(new Label(() -> version, VERSION_SCALE, Theme::getBodyFont, Theme::getMutedFg) - .position(width - EDGE - versionWidth, height - EDGE - (AccountChip.HEIGHT + versionHeight) / 2) - .animation(new Fade(AnimationConfig.mainMenu))); + draw(new Label(() -> version, VERSION_SCALE, Theme::getBodyFont, + () -> Theme.withAlpha(VERSION_ALPHA, Theme.getMutedFg())) + .position(EDGE, height - EDGE - versionHeight) + .animation(delayed(new Fade(AnimationConfig.mainMenu), EDGES_DELAY + EDGES_STAGGER * 2))); + } + + private static Animation delayed(Animation animation, int delay) { + animation.delay = delay; + return animation; } /** - * "Saturn Client 0.1.0 · Minecraft 1.21.11", from the mod version - * "0.1.0+1.21.11". + * "Saturn 0.1.0 · 1.21.11", from the mod version "0.1.0+1.21.11". */ private static String getVersionText() { String[] version = Providers.saturn.getModVersion().split("\\+", 2); - String text = "Saturn Client " + version[0]; - return version.length > 1 ? text + " · Minecraft " + version[1] : text; + String text = "Saturn " + version[0]; + return version.length > 1 ? text + " · " + version[1] : text; } private static void addMenuButton(AnimationStagger stagger, Element button) {