TextureButton, ClickableTexture, Text, Notification and the FadeOut and
SlideX animations only Notification used, Utils.getOrNull and the
commented-out notify, Element.duration, the 17 PNG icons the Lucide SVGs
replaced, and the Textures constants for them and for files that don't
exist.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
HUDs are drawn as they are in game, background included, through the
new HudModPreview.draw, and the world behind the editor isn't blurred.
Each has an outline that turns the accent color with the mod's name while
hovered or dragged, and a visible resize handle that's easier to grab.
Scale stays within its range and HUDs stay on screen, and a hint says how
to use the editor.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Buttons no longer have a primary style: every button is the translucent
outlined surface that brightens on hover, and only an icon button's icon
takes the accent color. The title screen's dock shows just its icons.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Button is now primary (accent fill) or secondary (a translucent outlined
surface), and IconButton is a square secondary button with a Lucide icon,
replacing the PNG TextureButtons. Neither is scaled with Element.scale any
more, which multiplied click positions instead of dividing them.
The Shift menu is the HUD editor, the mod menu (its button was labelled
"Settings") and cosmetics. The title screen centers the logo over a
compact stack of the game's menus, with the player, a dock of Saturn's
screens and the version along the bottom. The player chip shows the
player's face from their skin and whether they're connected to Saturn.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The slot index was taken before the middle slot was skipped, so page one
showed emotes 0-4 and 6-8: emote 5 never appeared and emote 8 showed on
two pages. Emotes now fill the eight cells around the middle in order,
and slots past the last emote aren't drawn, so they can't play a null
emote.
Emotes show as EmoteTiles: the preview in its own colors (it was tinted,
almost black on hover), the name under it, an accent outline on hover, and
an icon when an emote has no preview. The middle cell holds the page and
its arrows when there's more than one page. Emote names and cosmetic names
share Utils.nameFromId.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A "Background blur" setting (0-10, default 5) sets how much the game
behind Saturn's screens is blurred. Screens now only say whether to blur,
and SaturnScreen.getBackgroundBlur gives the setting's strength, faded in
over the screen's first 700 ms. The title menu still doesn't blur.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
CurveProperty holds the easing curves in the order Animation.getCurve
takes them, replacing three copies of the list in zoom, freelook and the
animation config; it's saved the same way. Its dropdown opens a
CurveOptions popup: a CurvePreview graph beside the list, with a dot
running along the hovered curve, or the current one.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Animations section shows each menu's duration, stagger and curve
under the menu's name instead of one flat list of 18 rows.
AnimationConfig keeps its name and lists every menu's config; it's saved
under the same keys as before, so existing settings keep loading.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ElementContext carries the part of the screen where an element can be
seen, passed down in a Frame and narrowed by each Scroll to its own box.
A dropdown opens below only if its list fits in that part, otherwise above
if it fits there, or else on the side with more room, so one at the
bottom of a scrolled list no longer opens past the list's edge.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Popup draws one element above the rest of the screen and gets mouse
events first; clicking or scrolling outside closes it. ElementContext now
carries each element's position on screen so an input inside a scroll can
open a popup beside itself.
Select is a dropdown: the current value opens an OptionList with the
current option ticked, scrolling for long lists and opening upward when
there's no room below. The color picker moved out of ColorInput into a
ColorPicker popup, so scroll areas no longer clip it and later rows no
longer draw over it, and all three of its parts can be dragged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Scroll kept its position as an int, so wheel and trackpad deltas were
truncated: small ones were lost in one direction and a wheel notch moved
one unit. It now keeps a fractional position, scrolls 24 units a notch,
sizes and places its thumb consistently, and the thumb can be dragged or
the track clicked. PanelScreen's scrollWidth and scrollContentWidth keep
every scrolling list clear of the bar.
Sliders read a float step from its text, so 0.1 no longer shows 17
decimals, and show at most three; number boxes show at most three too.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Properties can carry a one-line description, set with
NamedProperty.description for mods, a ConfigManager.property overload for
the client's config, and a helper in ModLayout. PropertyList rows show it
under the setting's name in muted text. Every mod, HUD layout, general,
UI style and animation setting now has one.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
IntProperty and FloatProperty can take an optional range, step and unit.
PropertyList shows those settings as a Slider: a track to click or drag,
snapping to the step, with the value and unit beside it. Zoom and freelook
levels and durations, fullbright brightness, the theme radii, animation
timings and HUD scale and radius get ranges; the rest stay number boxes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
CosmeticsMenu replaces the cloak and hat menus and stores: the player on
the left, turned by dragging, and on the right Cloaks and Hats tabs over a
grid of every cosmetic. Clicking an owned one equips it, and clicking one
not owned yet claims it, which is free. The equipped one is outlined and
badged, and the grid asks to connect when there's no Saturn session.
SkinPreview is now a drag-to-rotate player view, and its EntityDrawer draws
the player filling a box at a given yaw, returning false when there's no
player. CosmeticPreview and TabMenu go with the old screens.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ClientSettings replaces ConfigEditor: a section list on the left (General,
UI Style, Animations) and the chosen section's settings on the right, each
with a Reset for that section. UI Style shows four theme presets, the
theme colors as a two-column grid, then the radii and font.
New pieces: SectionNav, ThemePresetCard, ColorGrid and Theme.PRESETS.
Theme keeps its config like AnimationConfig does, Divider can be vertical,
and PropertyList's section titles are public.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A mod's settings button now opens ModSettings: a header with the mod's
icon, name, version, tags and description, a Reset button and an on/off
switch, then its properties as rows, with nested namespaces as titled
sections and a live preview card beside them for HUD mods.
PanelScreen holds the sidebar-and-panel frame that the mod menu, mod
settings and config editor share. PropertyList lays out any config as
rows. The inputs share one field look: Toggle is a switch, Select steps
with arrows, and the number, keybinding and color inputs are boxes. The
color picker opens to the left and closes on outside clicks.
Every property type now implements reset(), which was a no-op, and
ModLayout keeps its settings in order instead of Map.of's. ConfigEditor
moves onto the same frame and rows and drops its HUD preview, which added
a new element every frame.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The mod menu is now a translucent panel beside a navigation rail, with a
header showing how many mods are enabled, a search box, category filters
built from the mods' tags and a three-column grid of mod cards. Each card
shows the mod's icon, name and description with a settings button and an
on/off switch. The layout shrinks to fit smaller windows.
New reusable pieces: Panel, Label, ChipGroup, SearchInput,
Toggle.drawSwitch, Theme helpers for panel, border, muted text and body
font, and Fonts.ellipsize. The sidebar and card icons are Lucide SVGs, and
seven mod icons were redrawn in the same style.
Scroll can skip its background and be cleared, and no longer passes clicks
outside its bounds to children scrolled out of view. Input checks overflow
and places the cursor at the scale its text is drawn at. Screens that are
not redesigned yet move the wider sidebar so it keeps its gap.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
drawRoundedBorder draws an outline inset into the given bounds so it lines
up with a rounded rectangle of the same size and radius, and a new
drawRoundedRectangle overload draws both with separate background and border
colors. Both shapes share one SVG-to-texture helper.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Emotes loads assets/saturnclient/player_animations/*.json with
emotes-core into Saturn's own EmoteRegistry (not the library's shared
one, so other mods can't replace them), and lists the ones that loaded
for the wheel.
- The emote wheel now also sends the emote to the server, so other
players see it. It only played locally before.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The six 4096x4096 faces were 110 MB, about 90% of every mod jar
(121.7 MB per Minecraft version). That exceeded the 100 MB upload limit
in front of git.selimaj.dev, made every download huge, and cost ~400 MB
of GPU memory on the title screen. At 2048x2048 they're 33.5 MB (jar
~45 MB, ~100 MB GPU memory) and still sharp on 1440p/4K screens.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Stop sending the Minecraft access token to the Saturn server. The
connect loop now:
1. fetches GET /versions and compares this client's mod version:
supported -> connect; deprecated -> warn, connect; neither -> warn,
don't connect (warnings are shown once per status change)
2. requests auth_challenge with the username to get a server id
3. calls Mojang's session `join` with the access token and server id
(the token only goes to Mojang); a refused token gives up
4. requests auth_verify, which the server confirms with `hasJoined`
Add SaturnProvider.getModVersion() and showWarning() for the version
check and its toast.
Refs saturnclientmc/saturnclient#7
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Move to session-java 0.2.0 (Gitea package registry) and rework
ServiceClient around a single connect loop:
- Reconnect with exponential backoff (1 s -> 60 s) when the connection
drops, e.g. on every server redeploy; give up only when retrying cannot
help (no Minecraft session, or the server rejects the token)
- Publish the session only after authentication succeeds, and replace
(rather than append to) owned cosmetics and clear cached players on
reconnect
- Time out every request after 10 s and connecting after 10 s, so a lost
response can no longer hang the player-lookup worker forever
- Register onClientStopping once, and keep a local session reference in
request callbacks
- Allow -Dsaturn.serverUri to point the client at a local server
Refs saturnclientmc/saturnclient#4, saturnclientmc/saturnclient#5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
SaturnPlayer stored non-Saturn players as null, which looked the same as
"not fetched yet", so every render re-queued them and flooded the server
with get_player requests. Remember negative lookups and re-check them
after 60 s, retry failed lookups after 5 s, queue each player at most
once, skip lookups while disconnected, and replace the hand-rolled worker
thread with a single-thread executor.
getPlayer now returns null only when the server says the player isn't on
Saturn and throws on failure, so failures are retried instead of cached.
Make state shared between network callbacks and the render thread safe:
ConcurrentHashMap for players, CopyOnWriteArrayList for owned cosmetics,
volatile session/uuid and cosmetic fields, and run emote notifications
on the client thread.
Refs saturnclientmc/saturnclient#2, saturnclientmc/saturnclient#6
Co-Authored-By: Claude Opus 5.5 <[email protected]>