UI & Text
Variable-width font rendering, text control codes, overlay window management, dialogue flow, and menu system. The UI and text system is implemented in C.
Variable-Width Font (VWF) System
GB Studio uses a software-rendered variable-width font system, not hardware tile-based text. Characters are drawn into tile buffers at arbitrary pixel offsets, producing proportionally-spaced text on the Game Boy’s 8×8 tile grid.
Font Structure
Each font resource is stored as a banked data block with the following header:
typedef struct font_desc_t {
UBYTE char_start; // First character code (usually 32 = space)
UBYTE char_count; // Number of characters
UBYTE char_width; // Max character width in pixels
UBYTE char_height; // Character height in pixels
UBYTE name_length; // Length of font name string
// followed by: name, width table, glyph data
} font_desc_t;
- Banked resources: Fonts are loaded via
far_ptr_t(bank + address) - Width table: One byte per character, giving pixel width for proportional spacing
- Glyph data: 1bpp bitmap for each character
VWF Rendering Pipeline
- Characters are drawn into a temporary tile buffer
- Each character’s width advances the cursor by a variable amount
- When the cursor crosses a tile boundary, the completed tile is written to VRAM
- Rendering happens during
ui_update()in the main loop
Because VWF is software-rendered, text display is not instantaneous. Characters are drawn progressively across frames during ui_update(), which runs near the end of the main loop. Text speed controls how many characters are rendered per frame.
Text Control Codes
Control codes are embedded within dialogue text strings to modify rendering behavior. They are processed inline as the VWF engine encounters them.
| Code | Hex | Description |
|---|---|---|
| End of string | 0x00 | Terminates text |
| Newline | 0x01 | Move to next line |
| Speed (instant) | 0x02 | Set text speed to instant |
| Speed (value) | 0x03 + N | Set speed to N frames per character |
| Font change | 0x04 + bank + addr | Switch to different font |
| Goto tile | 0x05 + X + Y | Move cursor to tile position |
| Relative goto | 0x06 + X + Y | Move cursor relative |
| Set palette | 0x07 + P | Set text palette (0–7) |
| Wait for input | 0x08 | Pause until button press |
| Escape next | 0x09 | Print next byte literally |
| Variable ref | 0x0A + var_hi + var_lo | Insert variable value as text |
| Char ref | 0x0B + var_hi + var_lo | Insert variable value as character |
| Speed (fast) | 0x0C | Set fast speed |
| Clear window | 0x0D | Clear text area |
Text Palette
The text_palette global variable (UINT8, range 0–7) controls which of the 8 BG palettes is used for rendering text tiles.
- Default: 7 (last BG palette)
- In-text control: Can be changed via control code
0x07within text strings - Use cases: Colored text, ensuring contrast on dark backgrounds, stylistic variation
When displaying text over dark backgrounds, the default palette may not provide sufficient contrast. Use the 0x07 control code or set text_palette before rendering to switch to a palette with light-on-dark colors.
Overlay Window
The Game Boy hardware window layer is used for dialogue boxes, menus, and HUD elements. It is positioned independently of the background scroll and always renders on top of the BG and sprite layers.
Window Registers
win_pos_x,win_pos_y— current window position (engine variables)WX_REG,WY_REG— hardware registers (set by VBL_isr)MENU_CLOSED_Y=MAXWNDPOSY + 1(fromui.h) — window off-screen = inactive- Window uses its own 32×32 tile map, separate from the background
- Text is rendered into the window tile map by the VWF system
Window Management
ui_update()handles window animation (sliding up/down)overlay_cut_scanline— splits the screen between BG and window at a specific scanline
overlay_cut_scanline is defined in interrupts.c but not declared in interrupts.h. If you need to access it from plugin code, add a manual declaration:
extern UBYTE overlay_cut_scanline;
Dialogue System
The dialogue system combines the overlay window with VWF text rendering to display character dialogue, narration, and informational text.
Dialogue Flow
- Overlay window slides up from the bottom of the screen
- Text renders character-by-character using the VWF engine
- Player presses a button to advance to the next text block
- Window slides back down when dialogue is complete
GBVM Commands
| Command | Description |
|---|---|
VM_DISPLAY_TEXT | Display text in dialogue box with variable substitution |
VM_DISPLAY_TEXT_SET_ANIM_SPEED | Set text animation parameters (speed, delay) |
VM_OVERLAY_SHOW | Show the overlay window |
VM_OVERLAY_HIDE | Hide the overlay window |
VM_OVERLAY_MOVE_TO | Move overlay to a specific position |
VM_OVERLAY_SET_MAP | Set specific tiles in the overlay tile map |
Menu System
Menus are rendered in the overlay window using a combination of text and a cursor sprite to indicate the selected item.
VM_CHOICE— display a multiple-choice menu- Menu items are rendered as text in the overlay window
- A cursor sprite indicates the currently selected item
- Returns the selected index to a variable
Text Drawing Commands (GBVM)
The full set of GBVM commands related to text and overlay rendering:
| Command | Description |
|---|---|
VM_DISPLAY_TEXT | Render text with variable substitution |
VM_LOAD_TEXT | Load text into buffer (without displaying) |
VM_SWITCH_TEXT_FONT | Change the active font |
VM_OVERLAY_SET_MAP | Copy tilemap region to overlay |
VM_OVERLAY_SET_SUBMAP | Copy submap to overlay (with CGB attributes) |
Common Patterns
Setting Text Color for Dark Backgrounds
When dialogue appears over a dark scene, the default text palette (palette 7) may render text invisible. Prepend a palette change control code before the text, or set text_palette globally:
// Use control code 0x07 to change text palette inline
// In event script: prepend palette change before text
// Or set globally before displaying text
text_palette = 3; // Use BG palette 3 for text
Custom HUD with Overlay
Keep the overlay window visible during gameplay to display persistent HUD information:
// 1. Show overlay at specific position (non-modal so gameplay continues)
VM_OVERLAY_SHOW 0, 0, .UI_COLOR, .UI_NONMODAL
// 2. Write tiles to overlay
VM_OVERLAY_SET_MAP 0, 0, 20, 2, _ui_hud_tilemap
// 3. Overlay remains visible during gameplay
// Update individual tiles as values change
Use .UI_NONMODAL when the overlay should remain visible during gameplay (HUDs, status bars). Use the default modal mode for dialogue and menus where player input should be captured by the UI system.