Files
Dawn-Godot/.claude/docs/ui.md
T
2026-06-11 20:42:08 -05:00

5.6 KiB

UI System

Scene structure

RootUI (Control, fullscreen, always visible)
├── DebugMenu
├── PauseMenu
│   ├── PauseSettings
│   └── PauseMain
├── GameMenu
│   ├── GameMenuPartyTab
│   └── GameMenuItemsTab
└── VNTextbox

RootUI is a permanent child of RootScene and registers itself with the UI singleton on _enter_tree. Access its children via UI.TEXTBOX, UI.DEBUG_MENU, and UI.GAME_MENU.

UI singleton

UI (autoload) is the global access point.

Accessor Returns Notes
UI.TEXTBOX VNTextbox Bottom-screen dialogue box
UI.DEBUG_MENU DebugMenu Dev scene-jump overlay
UI.GAME_MENU GameMenu JRPG-style in-game menu
UI.dialogueActive bool true for the entire duration of a DialogueAction, including line transitions

dialogueActive is set by DialogueAction — it is broader than just "textbox visible." Movement blocks on both flags: UI.dialogueActive prevents movement even while the textbox is briefly hidden between lines.

VNTextbox

Bottom-anchored PanelContainer that reveals text character-by-character and paginates when content overflows 4 lines.

Showing text from code:

# Fire-and-forget
UI.TEXTBOX.setText("Hello world.")

# Await player dismiss — use this in cutscene callables
await UI.TEXTBOX.setTextAndWait("Hello world.")

Flow:

  1. setText resets reveal state and sets new text; textbox becomes visible automatically
  2. Player holds interact to speed up reveal; press again after reveal completes to advance page or close
  3. textboxClosing signal fires when the last page is dismissed
  4. setTextAndWait awaits that signal before returning

Input guard: EntityMovement._canMove() returns false while !UI.TEXTBOX.isClosed. Don't set text without also expecting movement to be blocked.

Signal: textboxClosing — emitted once per setTextAndWait call when player dismisses.

AdvancedRichText

RichTextLabel subclass (@tool) used inside VNTextbox. Handles:

  • Smart word-wrap (TextServer.AUTOWRAP_WORD_SMART)
  • Pagination via maxLines / startLine exports
  • Inline input icons: [input action=interact]text[/input] → replaced with the icon image from res://ui/input/{action}.tres
  • Optional auto-translation via Godot's tr()

Supported icon actions: interact, pause, debug, up, down, left, right.

ClosableMenu

Base class for any togglable panel. Extends Control; isOpen drives visible.

menu.open()    # shows, emits opened
menu.close()   # hides, emits closed
menu.toggle()

Signals: opened, closed.

All new menus that need standard show/hide behaviour should extend ClosableMenu.

Game menu

JRPG-style in-game menu at res://ui/gamemenu/. Open with the menu input (Tab on keyboard, Y on controller). Blocks player movement while open via EntityMovement._canMove().

Structure:

  • Left sidebar: ItemList tab selector (Party, Items)
  • Right panel: active tab content
Tab Content
Party One card per PartyMember — name, status, HP/MP, ATK/DEF/SPD/MAG/LCK
Items One row per ItemStack in PARTY.BACKPACK — item name + quantity

Both tabs are populated dynamically on open; call refresh() on the active tab directly if data changes while the menu is already open.

Key methods on GameMenu:

Method Effect
open() Shows menu, refreshes active tab, grabs sidebar focus
close() Hides menu
isOpen() -> bool Visibility state

ui_cancel or menu closes the menu. The menu input opens it only when UI.dialogueActive is false and the textbox is closed.

To add a new tab: add a value to GameMenu.Tab, create a tab scene/script under ui/gamemenu/, instance it in GameMenu.tscn as a sibling of the other tabs, add an @export for it in GameMenu.gd, and add the match branch in _selectTab().

Pause menu

PauseMenu wraps PauseMain (item list) and PauseSettings (settings tabs).

Method Effect
PauseMenu.open() Shows container, opens PauseMain
PauseMenu.close() Hides everything
PauseMenu.isOpen() -> bool Visibility state

ui_cancel inside the pause menu: if PauseSettings is open, closes it and reopens PauseMain; otherwise closes the whole menu.

Stub: Pause.gd (the singleton) has its logic commented out. Pause menu is not yet wired to actual game-pause state.

Settings menu

SettingsMenu is a shared tabbed component instanced in both MainMenuSettings and PauseSettings. Three tabs: Gameplay, Sound, Graphics — currently contain placeholder labels only.

Debug menu

DebugMenu (toggle via debug input — F1) provides four scene-jump buttons:

Button Action
Overworld SCENE.setScene(OVERWORLD)
Battle SCENE.setScene(BATTLE)
Cooking SCENE.setScene(COOKING)
Initial SCENE.setScene(INITIAL)

Access via UI.DEBUG_MENU. Starts hidden; isClosed getter/setter controls visibility.

Theme & assets

  • Global theme: res://ui/UI Theme.tres — applied to all UI nodes
  • Input icons: res://ui/input/{action}.tres — one file per action name
  • Font: configured globally in project settings

Adding a new menu

  1. Create a scene whose root extends ClosableMenu (or Control if open/close isn't needed)
  2. Add it as a child of RootUI.tscn
  3. Export a typed reference on RootUI.gd and wire it in the Inspector
  4. Expose via a getter on UISingleton.gd if other systems need access (follow the TEXTBOX / DEBUG_MENU pattern)