# UI System Source: `src/dusk/ui/` See also: `.claude/display-spritebatch.md`, `.claude/display-text.md`, `.claude/display-color.md` --- ## Overview The UI system renders overlaid interface elements on top of the scene each frame. It is called by the engine after the scene render pipeline and before the screen unbind -- game code does not drive it directly. All UI elements render through the global SpriteBatch. --- ## Lifecycle ```c extern ui_t UI; errorret_t uiInit(void); void uiUpdate(void); errorret_t uiRender(void); void uiDispose(void); ``` `uiUpdate` is called each game tick; `uiRender` is called each render tick. The engine calls both automatically -- do not call them from game scripts. --- ## Element registration (`uielement.h`) ```c typedef struct { uielementtype_t type; // UI_ELEMENT_TYPE_NULL or UI_ELEMENT_TYPE_NATIVE errorret_t (*draw)(); // draw callback } uielement_t; extern uielement_t UI_ELEMENTS[]; // registered element array ``` `uiRender` iterates `UI_ELEMENTS` and calls each element's `draw` callback. Elements register themselves during `uiInit`. --- ## Elements ### uiframe_t -- 9-slice border (`uiframe.h`) A resizable bordered panel rendered using 9-slice (9-patch) technique from a 3x3 tileset. ```c typedef struct { tileset_t tileset; texture_t *texture; } uiframe_t; errorret_t uiFrameInit(uiframe_t *frame); errorret_t uiFrameDraw( const uiframe_t *frame, const float_t x, const float_t y, const float_t width, const float_t height ); void uiFrameDispose(uiframe_t *frame); // does not dispose texture ``` `uiFrameDraw` pushes 9 quads (corners + edges + centre) to the SpriteBatch without flushing. The caller must call `spriteBatchFlush()` after all sprites for a draw pass are buffered. --- ### uitextbox_t -- typewriter dialogue box (`uitextbox.h`) A global single-instance dialogue box that displays text one character at a time with word-wrap and multi-page support. ```c extern uitextbox_t UI_TEXTBOX; errorret_t uiTextboxInit(void); void uiTextboxDispose(void); ``` **Setting text:** ```c uiTextboxSetText("Hello, world!"); // Automatically word-wraps and paginates. // Resets currentPage and scroll to 0. ``` **Tick update (called from script `update` or uiUpdate):** ```c uiTextboxUpdate(); // Advances typewriter by UI_TEXTBOX_SCROLL_CHARS_PER_TICK (1) each // fixed tick. Skipped on dynamic sub-ticks. ``` **Page control:** ```c bool_t uiTextboxPageIsComplete(void); // scroll revealed full page bool_t uiTextboxHasNextPage(void); // more pages remain void uiTextboxNextPage(void); // advance; no-op on last page int32_t uiTextboxGetPageCharCount(void); ``` **Events:** ```c // Fires when the current page is fully scrolled into view: UI_TEXTBOX.onPageComplete // Fires when the last page has been fully scrolled: UI_TEXTBOX.onLastPage ``` Subscribe via the event system (see `.claude/events.md`). **Limits:** | Constant | Value | |----------|-------| | `UI_TEXTBOX_TEXT_MAX` | 1024 chars | | `UI_TEXTBOX_LINES_MAX` | 64 lines | | `UI_TEXTBOX_LINES_PER_PAGE_MAX` | 3 lines per page | | `UI_TEXTBOX_SCROLL_CHARS_PER_TICK` | 1 char per tick | --- ### uifullbox_t -- full-screen colour overlay (`uifullbox.h`) An animated solid-colour overlay that covers the entire screen. Used for fade-to-black, scene transitions, and flash effects. Two global instances are provided: ```c extern uifullbox_t UI_FULLBOX_UNDER; // draws below scene content extern uifullbox_t UI_FULLBOX_OVER; // draws above all content ``` ```c void uiFullboxInit(uifullbox_t *fullbox); // Start a colour-to-colour transition: void uiFullboxTransition( uifullbox_t *fullbox, color_t from, color_t to, float_t duration, easingtype_t easing ); void uiFullboxUpdate(uifullbox_t *fullbox, float_t delta); errorret_t uiFullboxDraw(uifullbox_t *fullbox); // Draw is skipped entirely when alpha == 0. ``` `fullbox.onTransitionEnd` event fires once when the transition completes. Subscribe to it to chain scene transitions: ```c // Typical fade-out before a scene change: uiFullboxTransition( &UI_FULLBOX_OVER, COLOR_TRANSPARENT, COLOR_BLACK, 0.5f, EASING_OUT_QUAD ); eventSubscribe(&UI_FULLBOX_OVER.onTransitionEnd, onFadeComplete, NULL); ``` --- ### uiloading_t -- loading indicator (`uiloading.h`) An animated loading indicator with fade-in / fade-out transitions. Shown while asset batches are loading. ```c extern uiloading_t UI_LOADING; void uiLoadingInit(void); void uiLoadingUpdate(float_t delta); errorret_t uiLoadingDraw(void); // Fade in; callback fires when fully visible: void uiLoadingShow(eventcallback_t callback, void *user); // Fade out; callback fires when fully hidden: void uiLoadingHide(eventcallback_t callback, void *user); ``` `UI_LOADING_FADE_DURATION` is 0.5 seconds. `UI_LOADING_MARGIN` is 8px. `uiLoadingDraw` is a no-op when the indicator is fully transparent. --- ### uifps_t -- FPS counter (`uifps.h`) Debug FPS display. Measures real elapsed time between ticks and draws the average frame rate as text in the corner of the screen. ```c extern uifps_t UIFPS; errorret_t uiFPSDraw(); // also performs the measurement update ``` Intended for debug builds only. Draw it explicitly from a JS `render` hook or from a UI element -- it is not registered in `UI_ELEMENTS` by default.