Files
dusk/.claude/ui.md
T
2026-06-16 12:29:36 -05:00

5.2 KiB

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

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)

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.

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.

extern uitextbox_t UI_TEXTBOX;

errorret_t uiTextboxInit(void);
void       uiTextboxDispose(void);

Setting text:

uiTextboxSetText("Hello, world!");
// Automatically word-wraps and paginates.
// Resets currentPage and scroll to 0.

Tick update (called from script update or uiUpdate):

uiTextboxUpdate();
// Advances typewriter by UI_TEXTBOX_SCROLL_CHARS_PER_TICK (1) each
// fixed tick. Skipped on dynamic sub-ticks.

Page control:

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:

// 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:

extern uifullbox_t UI_FULLBOX_UNDER;  // draws below scene content
extern uifullbox_t UI_FULLBOX_OVER;   // draws above all content
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:

// 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.

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.

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.