Skip to main content

UI, HUD and localization

Notification HUD position editing​

Use Saturn's own HUD editing entry directly: by default, press right Shift in game to open HudEditScreen, or use /saturn hud open. System adds no separate settings-screen entry or key binding. SystemHudEntries.NOTIFICATIONS is registered as system.notification when the physical client initializes, and NotificationHudEntry connects Saturn's placement logic with AUI notifications. Drag the outer frame to move, and drag past a window-edge anchor to change the reference point; after selecting, fine-tune with the arrow keys, Shift + the arrow keys moves by 10 pixels, and the checkbox in the top-right corner controls visibility. Finish to return to the game. Use /saturn hud system.notification reset to restore the default anchor and offset.

Position, anchor and visibility are written by Saturn to the local config/saturn/hud.json and are not saved again in config/system. By default it stays horizontally centered, 6% from the bottom; when the content changes, the bottom anchor stays the same and the height grows upward. The width and maximum height are still controlled by the shared CSS, and the editor only moves the position without scaling the notification. Other anchors use Saturn's positioning and window-edge clamping, and the GUI scale and the AUI document scale are handled by GUI ↔ document coordinate conversion.

The editor uses Saturn's native drawing API to show a simplified passive preview box; it does not create notifications, handle business buttons or trigger the prompt sound or TTS, and it can be edited even when there is no active notification. The title is always drawn by Saturn outside the box and is not repeated inside it; the persistent card preview keeps only a short placeholder text. The size uses the committed layout of the most recent notification, and a default illustrative height is used while there is no notification yet. Real notifications still go through the original AUI document and shared CSS, buttons only interact in the chat bar, and the expand / fade-in animation and message queue logic stay unchanged. Hiding notifications pauses display and cancels the current speech without clearing the queue; re-enabling restores the current message.

The shared AuiHudEntry.apply only reads the committed raw size of the root panel, does not use the visual bounds after the scaleX animation and does not start recursive geometry measurement. It writes left/top/bottom only when the panel instance or the placement result changes, does not modify the transform and does not pan the AUI viewport. The registration entry is referenced only by SystemModClient, and a dedicated server loads neither the HUD editor nor the AUI types.

Notifications and persistent cards declare system_hud on the body, and the shared CSS clears the HUD's background color, background image, shadow and background filter and hides the root decorative pseudo-elements. AUI 1.2.9's HTML.normalizeDocumentMarkup discards the attributes of the original html tag, so an html class in the template cannot be relied on: AssistantThemes adds the same marker on the actual document root node, while the body transparency rule takes effect directly when the shared CSS is first loaded. Only the backgrounds of the notification panel and the quest cards themselves are kept, and ordinary pages keep their existing backdrop.

Persistent card HUD​

SystemHudEntries.DISPLAY_CARDS is registered as system.cards and is positioned and shown or hidden separately from notifications. By default it is 4 GUI pixels from the left and 22% of the height from the top; the shared CSS limits the width to min(360px, 38vw), sets no height limit, arranges cards downward by content and creates no scrollbar. Saturn positioning uses the actual content height as well. Drag "Persistent cards" in the Saturn editor, or run /saturn hud system.cards reset to reset the position; the layout is still written to Saturn's hud.json, and there is no new editing entry or position config in this mod.

Pinned quests are persisted and their progress refreshed by the server-side core DataStorage, and the client keeps only a mirror. The full quest list, the details and the persistent card share the pin state. After pressing the chat key you can view tooltips and unpin; opening another screen clears interaction immediately, and by default passive drawing is kept until the exit animation completes and only then unloaded, so that inventory buttons are not blocked. Showing it on other screens can be enabled in settings. F1 or logging out still unloads it immediately. The editor only draws the passive preview and creates no real cards or quest data requests. This HUD has no confirm button, automatic navigation or narration, and the notification queue keeps working independently. For the data flow and extension entry points, see Persistent card HUD.

When animation is enabled, the persistent card picks its entry and exit direction from the Saturn anchor: the left side enters and exits to the left, the right side to the right, and a vertically centered anchor chooses according to which half of the screen it is on. The wrapper layer uses a 280ms transform transition and a 180ms opacity transition, without modifying the width, height or position; it appears only after the native first layout completes. Unpinning, a screen switch that requires hiding, a hidden HUD or unreadable data waits for the exit to finish before deleting, and returning to the game or restoring the data during the exit enters in reverse; progress updates keep the wrapper layer and do not replay the animation. ScreenEvent.Opening updates the display target and the interaction state immediately, and the interactable state is also re-checked before mouse input; when hiding is needed, the document completes its exit on the new screen as an AUI persistent overlay, and no new cards are created during the exit.

"Settings → General → Persistent cards" provides two client toggles that take effect immediately and are saved to config/system/system-client.json: cardAnimations defaults to true, and when it is disabled entering and exiting switch straight to the final state and a running animation is cancelled as well; cardsOnOtherScreens defaults to false, and when it is enabled cards keep showing and refreshing on in-game screens such as the inventory and chests so that you can compare items, while the settings and pause menu screens stay hidden. Normal gameplay and the chat bar are always allowed; other screens are accepted only when Screen.isInGameUi() returns true, and the decision is not made with isPauseScreen() or by whether the game is actually paused. The chat bar needs separate permission because vanilla does not override its isInGameUi(). Other in-game screens only display without enabling card mouse hit-testing; the HUD editor always uses its own preview, and F1, logging out and Saturn visibility still take precedence. Switching mode or theme keeps both settings.

Screen structure and interaction​

Each feature's local commands, controls, pages and local actions are contributed by a ClientModule; the text, buttons and narration of a business card are described once by the corresponding CardData.buildCard, and no client-side card behavior table is registered any more. Full mode always shows the conversation, and the sidebar lists module entries directly without group headings or a "Conversation" button; usage statistics and settings sit in the top-right corner. Navigation still comes from the workspace declaration, and availability is controlled by the module IDs synced from the server. For the extension entry point, see Feature modules.

The JSON templates live in assets/system/cards and are parsed through CardNode's dispatch Codec; CardPresentation builds the local presentation uniformly. The Context flattens its three tables of state, parameters and callbacks, and CardBuilder / components copy an immutable snapshot. A single plain-text node with no buttons and no extra content is shown as an ordinary message; text with buttons is still a card. Simple mode uses numbered text selection, the HUD body shows BODY buttons, and FOOTER is generated by code; the resource pack only controls the layout. For the format, see Client JSON cards.

Quest cells, the shop, lottery pools and prize previews share CardGrid / CardPagination, with at most three rows, and the per-page capacity is computed automatically from the current mode's column count: 18 entries in full mode and 9 in notifications. Only the current page's nodes are created, so a long shelf does not build too much DOM and too many native icons at once; short results or the last page still keep the three-row area and the pagination bar, and a direction that cannot be paged is greyed out. Pagination is separate from the notification's bottom confirm buttons: it sends no request, does not switch notifications and does not replay speech; for the fields and extension approach, see Shared paginated grid.

A quest cell's formatted title arranges color segments through a centered flex wrapper, and the segments use width-constrained block text boxes, which keeps both single-line and wrapped text centered. AUI 1.2.9 does not apply the whole-line text-align to nested inline segments, so setting center on the outer element alone has no effect; the override here applies only to quest cell titles and does not change ordinary body text or the formatted text of other cards.

All screens share the layout and component styles of assets/apricityui/apricity/system/assistant.css and load the currently selected AUI theme. The full interface uses assistant.html in the same directory and is hosted by AssistantScreen. By default it uses a cyan-blue semi-transparent panel, thin borders and a warm gold accent; the module toolbar sits below the conversation log and above the input box, clicking the current module entry collapses it, and closing it does not trigger the query again.

The "General" page of settings embeds AUI's native <theme-switcher> and receives its aui-theme-change event; AssistantThemes writes the theme ID into ClientConfig and saves it immediately to config/system/system-client.json. AUI itself only switches the current document, so this mod applies the saved theme during page initialization and after a resource reload, and syncs the existing active system/ documents, covering the full, simple, settings and usage pages and the HUD. The old theme is replaced only after the new theme's styles load successfully, and a stale async result cannot overwrite a newer choice; the notification interaction state only adds and removes its own state classes and keeps the theme scope. The HUD root background and decorative pseudo-elements are always transparent or hidden, and the theme only draws the notification panel. Pages of other mods are unaffected.

Fixed text is written directly in the template and carried by AUI's <translation>key</translation>, which the document resolves in the current language during layout and drawing instead of Java writing it element by element; the module toolbar buttons, titles and descriptions therefore follow the template, and a custom template only needs to replace the markup to bring these texts along. Only texts that change with state (status, send, asr_toggle, the settings page state, usage_scope, usage_page, region names and recognition backend names), input placeholders (placeholder), aria-label and the language drop-down options are still provided by Java, because they are attributes or runtime values that node text cannot express. The child node's text is the complete key and cannot contain leading or trailing whitespace; when the key is missing, the raw key is shown directly, consistent with vanilla. AUI's text-align only affects the element's own direct text, so buttons whose content area is stretched and need centering (.settings_tab, .settings_modes button) switch to display:flex + justify-content:center, consistent with the existing .shop_controls button.

The daily sign-in toolbar uses a compact calendar mark, a small heading, a note on where rewards go and a sign-in button on the right; a narrow window allows wrapping. The heading and the note use element IDs to scope font size and spacing, so that a theme's large-heading style does not inflate the bottom action area. The copy does not assert in advance whether today is already signed in, and a duplicate sign-in still returns the existing record from the server.

The conversation scroll area uses a single-column grid with safe end alignment, and an inner normal-flow container holds the messages, so a short conversation stays near the input box while a long one can still be scrolled from the top. The committed scroll position is recorded before content or toolbar changes and restored after the unified render boundary finishes the new layout; when it was already at the bottom it follows new messages, and while reading history upward or still scrolling up it keeps the current and target positions instead of setting the offset directly to the total content height.

New messages in full mode appear with a 240ms, 18px upward shift plus a fade-in, using only transform / opacity and never changing the card height per frame. Bottom following reuses AUI's target-scroll easing, successively arriving messages update the target position, and scrolling up does not force it back to the bottom. The first open, window rebuilds and template reloads do not replay the historical entry animation; a busy-state-only change keeps the existing message nodes, and card updates are identified by UUID and are not treated as new messages.

A new row first completes its first layout with the transition-free message_new class, then switches to message_entering to play the animation, and the animation class is cleared when it ends. Ordinary buttons transition only background, text and shadow, overriding the transform / border-color transitions that come with the native theme; the border color still changes immediately with state, so AUI does not mistake the border-color interpolation for a layout change. The pin keeps its slanted / upright states without rotating interpolation, so a new quest list does not trigger a size measurement per button. For the sampling evidence, see Page layout audit.

Scroll ranges are read through AssistantGeometry from the committed scrollHeight, Rect and box-model margins, without calling Box.innerSize / Size.of or scroll-range probing APIs to re-measure the subtree. prepareRender is only called by native AUI drawing; AssistantPageScreen observes during the extract phase whether layout has completed, the input box, completions and HUD positioning read only valid geometry, and they wait for later frames when it is not ready. Scroll restoration opens its own GeometryQueryScope and keeps the behavior of registering easing in setScrollTop. Page turns, collapsing, section switches and pin updates only queue invalidation and do not re-layout synchronously inside the event. The full and simple pages keep unchanged cards, and the persistent HUD only replaces cards whose content changed; idle polling does not write the same text, display or interaction class again. For the evidence and the scope not yet accepted, see Page layout audit.

The client "System" key mapping is unbound by default; players can assign it themselves in the controls settings. Pressing it in game opens the currently selected full or simple interface, and pressing it again on any assistant system page returns to the game; other in-game screens are unaffected.

Page initialization keeps AssistantPages.prepare, which pre-warms the local CSS referenced by the template at the actual viewport before creating the document; waiting only for the DOM's readyState is not enough to wait for external styles. The full, simple, settings and usage interfaces share AssistantPageScreen, which requests the theme in the document context, binds listeners and fills content, and native AUI handles the subsequent layout. An empty draft does not set a cursor range; a non-empty draft waits for native layout to finish before positioning, preventing AUI's cursor scroll computation from triggering a full-page measurement early. The full page shell uses positioned boundaries to split the sidebar and the main area, and the body does not take part in flex measurement; the chat area keeps its original flexible layout inside. Changes to the completion popup are queued for the next native commit and do not additionally drive layout, animation or scrolling during the extract phase. HUD notifications reuse the style pre-warming and keep the style starting point of the hidden state and the original expand and fade-in animations.

HUD notifications use viewport-fixed positioning, keep a width of min(840px,94vw), have a default bottom edge of 6vh, and are positioned by the Saturn HUD layout; the body wraps, and the body, quest rows and items are all viewed inside the scroll area, whose height is about 10 body lines at most, the panel itself is at most 64% of the viewport, and overflowing content scrolls while the bottom actions are kept. The horizontal scale animation only handles expanding and collapsing. The internal mouse listener hangs on the notification panel and actively consumes events only when the chat bar is open and the current notification is fully visible; an ordinary AUI listener marks an event as consumed even when its callback performs no operation, so an ordinary listener cannot carry this condition. Every interaction-state refresh clears the HUD keyboard focus, a non-interactable state clears the pressed state, and the document is removed after the queue collapse completes.

AUI's global mouse-release key is managed by the dependency itself, and System no longer filters or scans other AUI documents with a Mixin. Notifications and persistent cards still interact through the vanilla chat bar. The voice key's held state is separate from input ownership: characters are suppressed only while the current recording session has not finished, is still active and belongs to the current interface, and losing focus or leaving the world clears the held state. The above is based on source code and static checks, and no game was started for acceptance.

The assistant name and introduction come from the system:system registry synced by the current connection, and the full interface's title / welcome area, the simple interface's speaker / idle introduction and the HUD notifications all share AssistantClient.system(). Both fields are translation keys resolved on the client; the binding text's parameters are the host name, the system name and the introduction in that order, and narration reads only the host name and the system name. A data pack does not deliver language files, so custom translations need a matching resource pack; for the format, see System definition.

The shared styles map text, panels, borders, buttons, accent color, corner radius and fonts onto AUI theme variables; the full interface, simple mode, HUD messages and the usage ledger use the same mapping, and layout differences are adjusted through body.simple, body.notification and body.usage rather than separate style files. The default t09-arwes-transparent also enables the t08-arwes base scope, keeping the originally darker main panel and warm gold accent, while other themes display their own palettes. The styles do not depend on external project paths.

Fonts prefer the selected AUI theme's --font-body; when the theme does not provide one, it falls back to Microsoft YaHei UI, Microsoft YaHei, Source Han Sans / Noto Sans, PingFang and generic sans-serif fonts installed on the client. The shared styles' result body text is 14px, helper notes are at least 12px, and headings and buttons use a weight of 600; a theme may also provide its own typography rules. This mod ships no font files, so the actual glyphs may differ between operating systems.

The full interface and simple mode use AssistantInputScreen to sync AUI input focus with Minecraft 26.1's text input state, so that the game does not shut the IME down every tick. The message, item search and shop search boxes all use the same logic; losing focus, closing the interface, switching mode or rebuilding the document releases the text input state without forcing a system language switch. IME pre-edit text uses Minecraft's native overlay, and the candidate area is converted from AUI document coordinates to GUI coordinates and positioned near the current input box; confirmed text continues to go through AUI's original character event handling.

During composition input only the native pre-edit overlay sets the candidate area, avoiding flicker caused by the interface and the overlay committing different rectangles every frame. Without composition it updates the area only after the input box position or the GUI scale changes. AUI's blur happens before the focus switch is committed, so the sync waits for the switch to finish; moving between editable input boxes keeps the IME session open.

The message box in both the full and simple interfaces is a single-line <input type="text">, focused automatically when opened, and Enter or the keypad Enter shares one submit path with the send button; Enter in the item and shop search boxes triggers the corresponding search. Holding Enter does not send repeatedly, and waiting for a response or blank input does not clear the draft. Sending, completion and arrow-key option switching are not performed during native IME composition or within 150ms after it ends, and confirming a candidate does not drop focus; the completion popup is hidden during composition.

AssistantCommandSuggestions provides prefix-based English text commands, Chinese aliases, the /system prefix, toggle parameters and the option numbers and quest names in the current reply on the client, without calling the network or the model; quest-related fixed commands are hidden when FTB is not connected. AssistantInputScreen shows completions only when the message box is focused, the cursor is at the end and there is no text selection, with at most 6 rows per display; the up and down keys switch, Tab or a click only fills the draft, only Enter executes, and Esc collapses the list. The completion node is a direct child of the body and uses a separate fixed popup that takes no part in the size computation of the input area or the panel. Candidates are hidden first when rebuilt, and during rendering they are positioned above the input box by its bounds, using the owning document's CSS pixels and a limited available height; when the position has not changed no style is written again. Layout queries, item tooltips and IME hot-zone computation all happen inside the Document.withContext scope, avoiding mixing viewport sizes from other documents or windows. The popup keeps using the single assistant.css; candidate content is set as plain text, and clicking a completion restores the original input focus without restarting the IME session.

The simple interface uses assistant-simple.html and is hosted by AssistantSimpleScreen: a bottom speaker box, the current request, the current reply and the input area; colors and fonts follow the shared theme. The panel uses fixed positioning, horizontally centered with its bottom edge fixed at 6vh, and does not rely on the body's flex end alignment, so a completion appearing, collapsing or changing candidates does not push the panel. It reads only the client's separate current snapshot, does not traverse the conversation list and does not load history; all business options are flattened into consecutive numbers, and Select 1 or /select 1 performs the same server action. It has only a send button, and the remaining features use text or commands.

Binding prompts, events, server notifications and replies after the interface closes are all managed by AssistantMessages, using assistant-message.html and the same assistant.css. It registers an ordinary AUI document through Document.create and is rendered by AUI's own HUD layer; the message itself has no Screen, input box or extra render layer, and it requests no mouse release, input focus or IME session. The page background is fully transparent, the notification width stays min(840px,94vw), the default bottom edge is 6vh, and after editing the Saturn anchor and offset are used; when the body and the extra list are too long they scroll inside the notification box, with the scroll area about 10 body lines high at most.

During normal gameplay pointer hit-testing is disabled on the whole DOM, so buttons are visible but do not accept input; after entering the vanilla ChatScreen, body.notification.interactive enables hit-testing only on the panel and its descendants. The template uses aui-mouse-events=passthrough and does not intercept vanilla events automatically according to document hit-testing; the panel's internal listener calls consumeNative() explicitly according to the interaction state. Pointer hit-testing rules use !important, so that a theme cannot re-enable hit-testing on the passive HUD. Opening a non-chat screen such as the inventory removes the notification document immediately; mouse press, release and interface scroll-wheel events check the actual interface again before AUI's global input dispatch and remove HUDs that should not exist, so that leftover documents do not block native controls such as the FTB sidebar. A click clears the AUI focus so that later Space / Enter is not swallowed by the button; closing chat immediately disables pointer hit-testing and buttons while keeping the same document and animation progress. The hint reads the chat key name from options.keyChat, defaults to T, and updates automatically after the user rebinds it.

After speech input is enabled, you can hold the voice key (F8 by default) while the notification is fully expanded to operate the current buttons without entering the chat bar; the hint also shows the actual bound key name. Buttons use fixed localization keys, and the example sentences and cached vectors match against the current button set, supporting "Confirm", "Close", "View quest details" and "Claim reward"; mouse and voice share the same execution entry. Recording and waiting for recognition keep the current notification and show the state and intermediate text in notification_voice; no input focus is requested. When the match is insufficient or the buttons are ambiguous, the main chat opens and reuses normal routing; when an action is busy, a hint appears inside the notification. Hiding, switching, confirming and logging out all cancel recognition for the original notification; for details, see Speech input.

The panel uses the shared CSS's transform: scaleX(...) to expand or collapse to the left and right within 240ms around the horizontal center, without changing the layout width or text wrapping. The title, body, buttons and hints are all placed in notification_content and fade in and out with a 160ms opacity transition. AssistantMessages manages the order in six phases: hidden, expanding, fading in, visible, fading out and collapsing, and each step waits for the previous animation to end through AUI Transition.isActive. The first open expands and then fades in; when a confirm, close or explicit action triggers a replacement, it fades out first, and only after the content is fully transparent is it replaced with the next item and faded in, while consecutive notifications keep the panel expanded. The visible phase has no countdown, and the end of narration does not switch the notification. When the queue is emptied, it fades out and then collapses and unloads; a new message received during the fade-out continues directly, and one received during the collapse expands in reverse and then fades in. Buttons are not interactive during animation phases. Mouse events are registered only once per document refresh generation, and switching messages does not mount listeners again. Other screens, F1, logging out and explicit cleanup still hide or unload immediately, keeping the original focus and lifecycle boundaries.

Every message always has "Confirm", and binding additionally has "Open System"; business notifications extract trusted actions from the server result and may offer "View details". Confirming removes the current item; server buttons by default wait for a direct reply and then replace the current notification in place, while other queued items keep their order; gift claiming keeps the current list, which the reply refreshes silently, and the list is removed only after everything is claimed. Business actions keep the original module and input, are still validated by server authorization and are disabled while the assistant is busy. Local buttons close or keep the notification as declared. There is no model-generated HTML or executable script.

The quest list's detail actions are rendered separately in notification_choices, showing the full list's consecutive numbers, names, chapters and progress line by line, without taking the two bottom business button slots; the bottom keeps "View details" and "Confirm", and the quest list no longer offers "Next page". The list reuses the shared CSS, can be scrolled after pressing T and any row can be clicked, and it is disabled during busy and animation phases; row actions still reference the corresponding server-side trusted actions, and speech falls back to the original ambiguity handling when it meets a detail action with the same name. Message deduplication compares both the row text and the action, so different quest lists are not merged merely because their body description is the same; switching notifications resets the list scroll position.

When the notification box first moves from hidden into the expanding phase it plays the vanilla-registered sound system:notification, and the body narration starts only after it finishes; synthesis is prepared in parallel during the prompt sound. Consecutive notifications only switch the body, a reverse expand in the middle of a collapse does not replay the prompt sound, and the next round prompts again only after a full collapse. The prompt sound is 75% of the narration volume, shares the Voice category and the current message session, and stops together when the notification is closed, hidden or switched. The prompt sound does not require automatic reading to be enabled or a cloud key to be configured; restoring a notification and refreshing the document do not replay it, for details see Speech synthesis and voice design.

Only after the server has successfully persisted a new binding is the fixed "Ding! Congratulations, host. The system binding succeeded." notification queued, with the actual system name, host name and system introduction in its body; the yellow title in the top-left corner is always the localized "System". Narration keeps "Ding!" together with the actual system name and introduction, and does not read the fixed title. There is no extra reasoning and no made-up first-binding reward, and a repeated grant shows an already-bound hint. The queue displays items in order, deduplicates by card ID, waits for at most 32 items and drops the earliest waiting item when full. Binding and ordinary notifications both persist until an explicit action or a server update; other screens or F1 unload the document, and the same notification is rebuilt on return, avoiding overlap with the simple interface. After a resource reload the text and buttons are refilled per document refresh generation. If the template is broken, it falls back to a chat message and releases that item, avoiding a retry every tick.

The body keeps the full content; long text, quest lists and item lists scroll separately within a limited height and are no longer truncated at 360 code points or 6 lines. Event and management notifications are recorded in the workbench conversation but do not overwrite the current interaction result or its number. The client message queue has no separate persistence or history interface, and logging out or a successful undo clears the active document and the waiting items, after which the undo hint is queued separately.

FTB quest completion and new quest unlocking reuse the same event path with the bilingual system.result.quest_completed / system.result.quest_unlocked templates, and the card carries the quest title, chapter and the existing system:quest_detail action. The completion notification adds a fixed "Claim reward" button according to each player's currently claimable rewards: a single ordinary reward is claimed directly, and multiple or self-selected rewards show the selection details. One quest produces one message; completed items are queued first and then unlocked items are queued in order; the simple interface's current reply is not overwritten. Both details and claiming can be performed through an explicit button or notification speech action, reusing the existing authorization and reference validation.

For quests that are unlocked and not completed and whose remaining objectives are all vanilla checkbox objectives, the unlock notification and the details card add a fixed "Complete this quest" action, and simple mode lists it as a numbered option as well. The notification speech example is registered under system.action.complete_quest; clicking and speech share system:quest_submit's checkbox-only mode, the server re-checks the current conditions, no items or experience are consumed, genuinely locked prerequisites are not skipped, and only the existing completion notification is shown after completion.

Only after a new binding succeeds, notifications are queued in the order "binding message → claimable starter gifts → overview of currently advanceable quests"; all matching gifts are merged into one notification, and missing gifts or quests are skipped. The overview shows the total number of ordinary advanceable quests and the first three, and "View quests" re-reads the full scrollable list without treating existing quests as newly unlocked one by one. Logging in again, granting twice, changing teams or reloading do not trigger the guide again, while a rebind after an undo can trigger it once more. The intro quest is filtered out of every system read entry; eligible checkbox item quests present all rewards grouped by source, without showing or narrating the source quest name, chapter or ID, reusing the item rendering, tooltip, scrolling and speech session. "View gifts" reads the same full list, and "Claim gifts" handles them in a batch by trusted reference; on success it updates silently and removes the claimed items, and on failure they stay in the list, with no extra success hint or ordinary quest completion notification. Newly unlocked gifts are merged once per batch per player.

The usage ledger uses assistant-usage.html and TokenUsageScreen and still loads only assistant.css. The AI summary and player details are read through separate network payloads; ordinary players see only themselves and administrators can view the whole server, and permissions are re-validated on every server query. The TTS / ASR panel always shows the current account's local records, updates in real time, is not uploaded to the server and is not mixed with other players' rows or the server-wide summary. Viewing does not depend on binding, does not enter the conversation and does not consume the model; for the statistics definitions and storage paths, see Usage statistics.

What is kept is the visual style. The old binding page, the data-driven feature list, the old HUD, the world window and the old completion dialog are no longer used. Opening /system syncs the personal preferences; automatic notifications all use the HUD messages described above and do not steal game focus.

Player, FTB and item text continue to be written as plain-text nodes through AssistantView.text/element, and FTBQ's § / & formatting is handled by the text node. AI knowledge Q&A and web answers switch to a separate system:markdown node: it reuses AUI's built-in parser, and then AssistantMarkdown's passive reader rebuilds only the preset presentation elements, plain text and vanilla URL click actions, without inserting model HTML, attributes or scripts into AUI directly. External images keep only the alt text and are not downloaded; the shared CSS unifies Markdown heading, list, quote and code styles. Action buttons and text numbers are still created by Java from business results, carrying fixed modules and inputs; the server keeps re-validating. For details, see Markdown body.

The vanilla § formatting and FTB's commonly used & formatting in FTBQ titles, chapters, descriptions, objectives and rewards are handled by the shared AssistantText, and the full interface, simple mode, HUD body and quest buttons share one path. FTBQ server-side titles keep their original text and are not parsed as client rich text; LegacyText first converts valid &0–&f, &k–&o and &r into vanilla formatting codes (both cases are supported), keeps unknown codes and escaped plain ampersands, and then reuses vanilla StringDecomposer.iterateFormatted. After an explicit line break it parses again from an empty style, so that color and bold affect only the current line; when a line wraps automatically because of width, the formatting continues. Independent fields such as the quest list's title, chapter, and objective and reward names append a reset code at concatenation boundaries through LegacyText.scoped, while separators, numbers, progress and state return to the interface's default style. Fixed span nodes are created per consecutive style and are given color, bold, italic, underline and strikethrough; §r / &r restore the current interface's default style without forcing black. Obfuscated style does not generate random gibberish, and other invalid or trailing incomplete § formatting codes are handled by the vanilla parsing rules. The body, line breaks and Unicode characters are still written through setTextContent, and HTML tags in quest text are shown as text only. Format nodes keep the inline layout and the original button click target, and no style file is added. TTS uses the same conversion entry to extract plain text and does not read either kind of control code.

The conversation, pending requests, server preferences and capabilities, and the current result are all kept in the immutable AssistantClientState, which interfaces read through AssistantClient.state(); on client logout or a successful undo it is replaced with EMPTY directly, while the refresh version keeps incrementing. AssistantClient keeps network, navigation and speech side effects, and responses are delivered only to the original connection generation. Server history and preferences are read per player; closing the window does not roll back rewards already credited. The input area limits the length and does not submit repeatedly while waiting, but the server still rate-limits independently.

The full interface's history panel returns at most 24 complete messages, and an oversized result keeps only the complete cards that fit, with the whole response also length-limited; the serialized JSON is never truncated. The conversation scroll container and each message use ordinary block layout, and long cards take up space according to their full content; message spacing is controlled by margins, avoiding nested vertical flex measurement that pushes following messages into the previous card. Items, rewards in quest details and self-selected options keep their pagination actions, while the quest list and the name candidate list become fully scrollable lists, and ordinary reward buttons show the corresponding reward name. The quest list uses compact numbered rows showing only the name, chapter and percentage; rows are clickable in the full interface, and the simple interface offers "View 1" or "View name". The list and the candidate list do not show nested objectives and rewards, and the details paginate the description, objectives and rewards separately; bounded details are no longer affected by the generic card's 6000-character truncation.

The shop in the full interface has a sidebar entry, a search toolbar, offer shelf cards and a separate confirmation card; simple mode completes the same flow with text and numbers. The shelf lists at most 128 offers and, when there are more, shows a hint that only the first part is displayed. Prices use the Saturn Cost snapshot evaluated on the server; a single-item cost shows an icon, while resource, tag and other costs use text; the purchase action is hidden when no bill can be produced. The quote token is not shown in the card body, and no fictional balance is displayed.

The lottery page and the shop share a stretchable search bar: the input box fills the remaining width, and the search and all-pools buttons have equal height and are not compressed; in a narrow window the input box takes its own row and the buttons split the width below. Helper notes use a 12px font size. Pool cards and shop redemption cards share the item table: the same system:items node describes a shelf-style grid through columns (column count, 0 for inline flow), cell (slot width) and icon (icon size), with equal-height slots aligned by column and empty slots keeping the grid width; only the result items are shown, per-draw cost or required payment is no longer listed separately, and the cost becomes a vanilla tooltip line when hovering a result item. The redemption confirmation card (quote) still shows the required payment and the payment material groups in its body. IDs are demoted to secondary text; the lottery details' prize shelf shows prize names and item icons, with the chance and the full item list in the tooltip, no longer stacking weights and nested data fields. The full interface chooses the card body by CardView.template, and simple mode and the HUD share the corresponding compact text and item previews; all actions still carry the original trusted actions, and quotes and the separate confirmation flow are unchanged.

Each CardData provides item preview parameters in buildCard, AssistantItems renders them uniformly, and full cards, the simple mode's current reply and HUD notifications share AUI's native <item>. Item lookup shows the default item by registry ID; sign-in candidates, rewards and the inbox, shop offers and payment materials, and lottery costs and prizes use the actual ItemStackTemplate, keeping custom names, enchantments, durability and other components. Cards show icons, names and counts by group, notifications use compact icons with a count badge, and when there are many items you can press T to enter chat and scroll through them; an empty preview area is hidden. Icons follow the original document layout, clipping and fading and add no separate drawing layer or new style file.

Item models are scaled to 1.75 times their original size through the shared CSS with 40px of outer space; increasing only the <item> width and height does not change AUI's default 16px model, so the scale is applied to the native node. Quest details merge ordinary item rewards into the line below the "Rewards:" heading, arranging small cards directly, so that the item name and count no longer appear again above; the claim state moves into each small card's secondary text. Starter gift notifications show only item icons and a count badge without the "claimable" or "not yet claimable" status text; a claim failure still shows the corresponding error. Non-item rewards keep their text, and self-selected rewards are still grouped by candidate. The body of simple mode and notifications likewise omits the ordinary reward rows already shown by the small cards; the plain-text format can still obtain the complete summary separately.

Pool browsing and the shop share the same shelf card (system:offer_grid): one cell per pool, showing the icons of up to 2 rarest prizes and the pool name; clicking a cell requests that pool's details, and quotes are still evaluated on the server on demand. Hovering any item in a cell shows the list of the whole pool: up to 10 prizes taken by ascending chance, then arranged by descending chance, each with the prize name, chance and items, and when there are more than 10 the first line notes that only the rarest part is listed. The details card lists that pool's prizes with the same shelf node; here hovering shows only the current item — the vanilla item tooltip (name, enchantments, description and so on, taken from ItemStack) plus that prize's chance, and the whole-pool list is not repeated. The per-draw cost becomes its own line above the card body (the priced state), and a free pool does not show that line. Sign-in candidates are all placed in the candidate reward area, and item cards carry the name of the reward bundle they belong to; sign-in results, lottery results and the inbox keep using the small reward cards, the shop redemption card shows only the offer, and the required payment moves to the tooltip and the confirmation card. Simple mode and notifications likewise use the icon area, and prize names and item lists are not expanded again in the body.

Hovering an icon submits the vanilla item tooltip through GuiGraphicsExtractor.setTooltipForNextFrame, keeping advanced tooltips and NeoForge tooltip extensions. Both the input interfaces and the HUD use the vanilla delayed tooltip phase; the HUD submits the AUI interface state early in the chat interface's Render.Foreground, so that the tooltip extracted afterwards sits above the notification. AUI itself deduplicates submissions by the same frame's extractor, adding no second interface draw and not handling the IME pre-edit overlay again. Notifications respond to hovering only in the interactable fully visible phase, and the previous item tooltip is not kept after confirming, switching or collapsing; the mouse is not captured during gameplay.

FTB details and completion / unlock notifications sync ordinary item reward previews through a Codec, keeping the invisible and blocked reward filtering; self-selected options in details use QuestChoiceOutput to carry each candidate's name and items, keeping pagination, option order and claim references in correspondence. ItemPreviewOutput separates the display count from the item template, FTB base templates take a count of 1, and the count badge uses FTB's fixed value or random range directly, so that an oversized count does not exceed the template Codec's single-stack range. Previews do not trigger reward granting, do not expand non-item rewards specific to other mods, and do not traverse the whole self-selection pool in a notification.

The bilingual files are assets/system/lang/en_us.json and zh_cn.json, and their key sets must be exactly the same. New states, fields or buttons must be maintained in both files. Item names that come from the registry are still affected by the server language, and FTB's original localization components have no dedicated client translation protocol yet.

The unified settings use assistant-settings.html; General, speech narration and speech input switch tabs within the same document, it still loads only assistant.css, and it reuses AssistantInputScreen's native IME lifecycle; a page without the chat input box does not register message completions or Enter sending. Keys use AUI's password input box and are stored only on the local machine. Fixed text is translated on the client first and then sent to TTS; the language follows the game language by default and also supports automatic or explicit selection, with Qwen3 using language_type and Qwen-Audio using language_hints. The narration page also has a whole-sentence audio cache toggle that is off by default. The interface and the current notification each hold their own speech session: a new reply replaces the old reading, and closing or switching interfaces cancels it; confirming, acting on or hiding a notification also cancels it immediately. The end of narration does not switch notifications, and a manual switch does not wait for the speech to finish. Restoring a notification and history do not replay, and the playback state distinguishes vanilla from the OpenAL fallback. The English and Chinese language files keep identical key sets. For the specific parameters, voice compatibility and tool usage, see Speech synthesis and voice design.

The "Synthesis language" on the speech narration page uses AUI's native drop-down select, listing the follow-the-game-language option, automatic detection and all supported languages, with option names localized on the client. The choice is saved automatically to the existing language field right away; the disabled logic still applies while no API key is filled in. The drop-down keeps the font, border and focus styles of the single shared CSS, and the popup options use AUI's native overlay.

"Narrate quest details", "Narrate quest rewards" and "Narrate quest background" on the same page reuse the shared assistant_switch, save automatically right after a change, and default to details and rewards on and background off. With details off only the name and rewards are read; turning it on appends the requirements, and the background also needs its own switch and must pass the server-side narration filter. Empty descriptions, purely operational explanations or uncertain content are not narrated as background, and the filter result is persisted by the quest's unique ID and language. When it is the current speech session's turn, read-only text is requested by the trusted quest ID, the model reply is not written into the conversation or used to replace the card, and the notification animation is not reset. Item names are expanded on the client through vanilla Components; optional objectives and count ranges are formatted separately, and the existing small item cards and tooltips are unchanged.

For the system text tone, prompts and public reference sources, see Copy and prompts. The fixed UI templates handle the settlement notifications, and the model only fills in the restricted sign-in choice reason; no extra model turn is added for tone.

The search card first shows only the condensed answer and a "Sources and summaries" collapsible heading. The generic details node is collapsed by default, and clicking it shows the source titles and summaries; the link node turns the source title into a clickable link, reusing Minecraft's vanilla URL validation, link toggle and confirmation flow. Both share assistant.css and are clickable in full and simple mode, while the HUD responds only when the chat bar is open and the notification is interactable. Expanding does not request again or narrate, and after returning or rebuilding the page the state is initialized from the JSON's open value.

The collapsible and link buttons use a separate text child element, the arrow keeps a fixed placeholder, and expanding re-lays out the content subtree immediately. Search sources are arranged vertically as separate blocks, separated by dividers; summaries show at most a three-line preview and longer text is omitted, and clicking the title opens the original web page. The server compresses consecutive whitespace in summaries and does not fill the card with the web page's raw paragraphs.

The settings page's history, automatic reading, notification sound, audio cache, speech input and send-after-recognition all use the shared assistant_switch toggle style, including the slider displacement, switch colors, focus and disabled states. "Notification sound" sits at the top of the speech narration page, is on by default, needs no key and is independent of automatic reading; when it is off the body is narrated directly, and consecutive notifications still do not replay the prompt sound. Toggling writes SpeechConfig.notificationSoundEnabled and saves immediately, and an old config missing the field defaults to on. Underneath it uses button type=button role=switch, avoiding AUI's native checkbox drawing overlapping the track; the transparent checkbox overlay is no longer used. AssistantView.bindSwitch uniformly handles clicks, disabled checks and state switching, and switchChecked drives styling, accessibility semantics and form reads at the same time through aria-checked. Buttons support Enter / Space activation, the track and text do not receive pointer input, and the whole row button is clickable. All labels save automatically after a change, and TTS keeps only preview and stop buttons. Other interfaces can reuse the same structure and CSS without adding another style sheet. Full / simple mode still uses segmented buttons.

The settings page's content area, tabs and setting groups use ordinary block flow, the scroll area gets its space from a fixed-size shell, and long content scrolls inside; the native theme selector is positioned in the group's top-right corner and does not take part in the flex measurement of the content height. Switches use block-level buttons and an absolutely positioned fixed track, and the slider transitions through left, so that AUI does not call Size.of early while parsing a transform transition. Tab switches and control refreshes only commit the changed class, aria-selected, display and disabled, and the save logic stays unchanged. For the evidence, logs and the scope not yet accepted, see Page layout audit.

This round only checked the template structure, ID bindings, resource paths and language keys, without running in-game rendering. The actual sizes, scrolling, input focus and different GUI scales still need client acceptance after the user specifies the scope.

The assistant input box applies completions through Brigadier's replacement range and keeps the / and /system prefixes as well as the original arguments. Local candidates are shown first, and suggestions from the server command tree synchronized by the connection are merged in asynchronously, without waiting for the network before popping up. A reply must match the current page document, connection, command tree, draft, cursor, state version and IME state, so that a stale suggestion does not overwrite new input; keys still use Tab to accept, up and down to select, Escape to collapse and Enter to send. When MC cancels the previous remote completion itself, the local quest / button candidates remain available and are not cleared because of it.

Conversation mode menu​

The left of the full / simple send box shares ConversationModeSelector, with a large name and a small description, defaulting to standard. The popup is absolutely positioned upward and does not take part in the message area layout; it updates the selection and permissions only when the state revision changes, and disabled items are greyed out with color rather than opacity compositing or active measurement. It supports closing by clicking outside, Esc to collapse, the up and down keys to select and Enter / Space to activate. Administrator settings are delivered with AiStatus, and the server re-checks preference changes and execution authorization. For details, see Execution modes.