Add claude docs

This commit is contained in:
2026-06-16 12:29:36 -05:00
parent ed5c60ac30
commit c0a2ae234f
9 changed files with 935 additions and 0 deletions
+31
View File
@@ -75,6 +75,37 @@ if(DUSK_TARGET_SYSTEM STREQUAL "psp")
endif() endif()
``` ```
## Embedding JS files (`dusk_embed_js`)
Source: `cmake/modules/duskjs2c.cmake`
The `dusk_embed_js()` CMake function embeds a `.js` source file as a
C string constant in a generated header. It is used to ship script
module code alongside the engine binary without a separate file load.
```cmake
dusk_embed_js(
TARGET ${DUSK_LIBRARY_TARGET_NAME}
JS_FILE path/to/mymodule.js
# NAME is optional; defaults to uppercase stem + "_JS"
# e.g. "mymodule.js" -> "MYMODULE_JS"
NAME MY_CUSTOM_NAME
)
```
The generated header is placed in
`${DUSK_GENERATED_HEADERS_DIR}/<stem>_js.h` and defines:
```c
static const char MY_CUSTOM_NAME[] = "... js source ...";
static const size_t MY_CUSTOM_NAME_SIZE = sizeof(MY_CUSTOM_NAME) - 1;
```
Under the hood it calls `python -m tools.js2c` from the repo root.
The header is generated at build time; include it in the `.c` file
that registers the JS module, then pass `NAME` and `NAME_SIZE` to
`jerry_eval()` (or the equivalent module load helper).
## Tests ## Tests
- Test files live in `test/` mirroring the `src/dusk/` structure. - Test files live in `test/` mirroring the `src/dusk/` structure.
+92
View File
@@ -0,0 +1,92 @@
# Console
Source: `src/dusk/console/`
---
## Overview
The console is a lightweight in-engine debug overlay. It maintains a
fixed-size ring buffer of text lines and can render them to the screen
as an overlay. On Linux (where `DUSK_CONSOLE_POSIX` is defined), it
also reads commands from stdin on a background thread, allowing
interactive input during development without pausing the game loop.
---
## Limits
| Constant | Value |
|----------|-------|
| `CONSOLE_LINE_MAX` | 512 chars per line |
| `CONSOLE_HISTORY_MAX` | 16 lines in the ring buffer |
| `CONSOLE_EXEC_BUFFER_MAX` | 32 pending execution slots |
---
## Global state
```c
typedef struct {
char_t line[CONSOLE_HISTORY_MAX][CONSOLE_LINE_MAX]; // ring buffer
bool_t visible;
#ifdef DUSK_CONSOLE_POSIX
threadmutex_t printMutex; // guards ring buffer on POSIX targets
#endif
} console_t;
extern console_t CONSOLE;
```
---
## API
```c
void consoleInit(void);
// printf-style print into the ring buffer.
// Thread-safe on POSIX (uses printMutex).
void consolePrint(const char_t *message, ...);
// Process any queued script input lines. Must be called from the
// main thread once per frame.
void consoleUpdate(void);
// Draw the ring buffer as an overlay in UI space.
errorret_t consoleDraw(void);
void consoleDispose(void);
```
---
## POSIX stdin mode (`DUSK_CONSOLE_POSIX`)
On Linux only (`DUSK_CONSOLE_POSIX`), the console launches a background
thread that polls stdin using `poll()` at 75 ms intervals
(`CONSOLE_POSIX_POLL_RATE`). Lines typed at the terminal are queued
and dispatched on the main thread by `consoleUpdate()`.
This allows typing commands or JS expressions into the running game
without blocking the render loop. The ring buffer is protected by
`CONSOLE.printMutex` so `consolePrint` is safe to call from either
thread.
POSIX mode is not available on PSP, Vita, or Dolphin targets.
---
## Notes
- `CONSOLE.visible` controls whether `consoleDraw` renders anything.
Toggle it from a debug keybind or always set it to `true` in
development builds.
- `consolePrint` wraps lines at `CONSOLE_LINE_MAX` -- long messages are
truncated. Use multiple calls for long output.
- The console is distinct from the error system (`errorThrow` /
`errorPrint`). Use `consolePrint` for diagnostic output; use
`errorThrow` for recoverable failures.
- Log calls (`logDebug`, `logError`) go to the platform's debug output
(stdout/stderr), not to the console ring buffer.
+88
View File
@@ -0,0 +1,88 @@
# Display -- Color
Source: `build/generated/display/color.h` (generated at build time)
---
## Overview
`color.h` is a generated header. It is not hand-edited -- the source
lives in the CMake generator that produces it from platform configuration.
Include it via `"display/color.h"`.
---
## Types
```c
typedef float_t colorchannelf_t; // float channel [0.0, 1.0]
typedef uint8_t colorchannel8_t; // 8-bit channel [0, 255]
typedef struct { colorchannelf_t r, g, b; } color3f_t;
typedef struct { colorchannelf_t r, g, b, a; } color4f_t;
typedef struct { colorchannel8_t r, g, b; } color3b_t;
typedef struct { colorchannel8_t r, g, b, a; } color4b_t;
typedef color4b_t color_t; // default: RGBA uint8
```
`color_t` is always `color4b_t` -- four `uint8_t` channels.
Most engine APIs (text rendering, UI, mesh vertices) take `color_t`.
---
## Constructors
```c
color3f(r, g, b) // float RGB
color4f(r, g, b, a) // float RGBA
color3b(r, g, b) // uint8 RGB
color4b(r, g, b, a) // uint8 RGBA
color(r, g, b, a) // alias for color4b
colorHex(0xRRGGBBAA) // unpack 32-bit hex into color4b
```
---
## Predefined constants
Each named colour comes in four variants: `_4B` (uint8 RGBA, default),
`_3B` (uint8 RGB), `_4F` (float RGBA), `_3F` (float RGB). The bare
name (e.g. `COLOR_BLACK`) always resolves to the `_4B` variant.
| Constant | RGBA (uint8) |
|----------|-------------|
| `COLOR_BLACK` | 0, 0, 0, 255 |
| `COLOR_WHITE` | 255, 255, 255, 255 |
| `COLOR_RED` | 255, 0, 0, 255 |
| `COLOR_GREEN` | 0, 255, 0, 255 |
| `COLOR_BLUE` | 0, 0, 255, 255 |
| `COLOR_YELLOW` | 255, 255, 0, 255 |
| `COLOR_CYAN` | 0, 255, 255, 255 |
| `COLOR_MAGENTA` | 255, 0, 255, 255 |
| `COLOR_ORANGE` | 255, 165, 0, 255 |
| `COLOR_PURPLE` | 127, 0, 127, 255 |
| `COLOR_GRAY` | 127, 127, 127, 255 |
| `COLOR_LIGHT_GRAY` | 191, 191, 191, 255 |
| `COLOR_DARK_GRAY` | 63, 63, 63, 255 |
| `COLOR_BROWN` | 153, 102, 51, 255 |
| `COLOR_PINK` | 255, 191, 204, 255 |
| `COLOR_LIME` | 191, 255, 0, 255 |
| `COLOR_NAVY` | 0, 0, 127, 255 |
| `COLOR_TEAL` | 0, 127, 127, 255 |
| `COLOR_CORNFLOWER_BLUE` | 99, 147, 237, 255 |
| `COLOR_TRANSPARENT` | 0, 0, 0, 0 |
| `COLOR_TRANSPARENT_WHITE` | 255, 255, 255, 0 |
| `COLOR_TRANSPARENT_BLACK` | 0, 0, 0, 0 |
---
## Notes
- `color_t` uses premultiplied-friendly `uint8_t` channels for
compatibility with both OpenGL texture uploads and GX on Dolphin.
- For shader uniforms that expect float colours, convert manually:
`(float_t)col.r / 255.0f` etc.
- The `COLOR_SCRIPT` macro is a C string containing the JS Color class
static methods. It is concatenated into the embedded JS runtime
during module init (see `.claude/script.md`).
+240
View File
@@ -0,0 +1,240 @@
# Display -- Mesh
Source: `src/dusk/display/mesh/`
See also: `.claude/display-spritebatch.md`, `.claude/display-shader.md`
---
## Overview
The mesh system wraps platform-specific GPU geometry buffers behind a
common `mesh_t` type. Geometry is described as an array of
`meshvertex_t` values and a primitive type. The platform layer
(`meshplatform.h`) provides the concrete buffer and draw implementation
(VBO on OpenGL, display list or immediate-mode on Dolphin GX).
---
## Vertex format (`meshvertex.h`)
```c
typedef struct {
#if MESH_ENABLE_COLOR
color_t color; // optional per-vertex colour (disabled by default)
#endif
float_t uv[2]; // texture coordinates (U, V)
float_t pos[3]; // position (X, Y, Z)
} meshvertex_t;
```
`MESH_ENABLE_COLOR` is a compile-time flag (default 0). Enable it with
`-DMESH_ENABLE_COLOR=1` at CMake configure time if per-vertex colouring
is needed; be aware this changes the struct size and breaks binary
compatibility with pre-built mesh data.
---
## Core API (`mesh.h`)
```c
// Platform alias -- do not use meshplatform_t directly.
typedef meshplatform_t mesh_t;
typedef meshprimitivetypeplatform_t meshprimitivetype_t;
// Upload vertices to the GPU. Must be called from the main thread.
errorret_t meshInit(
mesh_t *mesh,
const meshprimitivetype_t primitiveType,
const int32_t vertexCount,
const meshvertex_t *vertices
);
// Flush a range of updated vertices to the GPU (modern targets only).
// vertexCount == -1 flushes all vertices.
errorret_t meshFlush(
mesh_t *mesh,
const int32_t vertexOffset,
const int32_t vertexCount
);
// Draw the mesh. vertexCount == -1 draws all vertices.
errorret_t meshDraw(
const mesh_t *mesh,
const int32_t vertexOffset,
const int32_t vertexCount
);
// Compute the axis-aligned bounding box.
void meshGetBounds(const mesh_t *mesh, vec3 outMin, vec3 outMax);
int32_t meshGetVertexCount(const mesh_t *mesh);
errorret_t meshDispose(mesh_t *mesh);
```
On constrained targets (GameCube/Wii) `meshFlush` is a no-op -- the
hardware reads vertices from main memory directly. Always call it on
desktop/mobile targets after modifying vertex data.
---
## Primitive generators
Each generator provides:
- A `*Buffer(vertices, ...)` function that writes into a caller-supplied
`meshvertex_t` array (no allocation).
- A global pre-built `*_MESH_SIMPLE` singleton + `*_MESH_SIMPLE_VERTICES`
array initialised at engine startup (for common one-off uses).
All generators use CCW winding and `MESH_PRIMITIVE_TYPE_TRIANGLES`.
### Quad (`quad.h`)
```c
#define QUAD_VERTEX_COUNT 6 // two triangles
// 2D quad in XY plane:
void quadBuffer(
meshvertex_t *vertices,
const float_t minX, const float_t minY,
const float_t maxX, const float_t maxY,
const float_t u0, const float_t v0,
const float_t u1, const float_t v1
);
// 3D quad using full vec3 min/max:
void quadBuffer3D(
meshvertex_t *vertices,
const vec3 min, const vec3 max,
const vec2 uvMin, const vec2 uvMax
);
extern mesh_t QUAD_MESH_SIMPLE;
```
The SpriteBatch is built on `quadBuffer3D` internally.
### Cube (`cube.h`)
```c
#define CUBE_VERTEX_COUNT 36 // 6 faces x 6 vertices
// Axis-aligned box from min to max:
void cubeBuffer(
meshvertex_t *vertices,
const vec3 min, const vec3 max
);
extern mesh_t CUBE_MESH_SIMPLE; // unit cube (0,0,0) to (1,1,1)
```
### Plane (`plane.h`)
```c
#define PLANE_VERTEX_COUNT 6
typedef enum {
PLANE_AXIS_XY, // flat in XY, normal along +Z (billboard / wall face)
PLANE_AXIS_XZ, // flat in XZ, normal along +Y (ground / floor)
PLANE_AXIS_YZ, // flat in YZ, normal along +X (side wall)
} planeaxis_t;
void planeBuffer(
meshvertex_t *vertices,
const planeaxis_t axis,
const vec3 min, const vec3 max,
const vec2 uvMin, const vec2 uvMax
);
extern mesh_t PLANE_MESH_SIMPLE; // unit XZ plane (0,0,0) to (1,0,1)
```
### Sphere (`sphere.h`)
```c
#define SPHERE_STACKS 8
#define SPHERE_SECTORS 16
#define SPHERE_VERTEX_COUNT (SPHERE_STACKS * SPHERE_SECTORS * 6)
void sphereBuffer(
meshvertex_t *vertices,
const vec3 center,
const float_t radius,
const int32_t stacks,
const int32_t sectors
);
extern mesh_t SPHERE_MESH_SIMPLE; // unit sphere centered at (0,0,0), r=0.5
```
### Capsule (`capsule.h`)
```c
#define CAPSULE_CAP_RINGS 4
#define CAPSULE_SECTORS 16
// Total vertex count = (2 * capRings + 1) * sectors * 6
void capsuleBuffer(
meshvertex_t *vertices,
const vec3 center,
const float_t radius,
const float_t halfHeight, // half-height of the cylindrical section only
const int32_t capRings,
const int32_t sectors
);
extern mesh_t CAPSULE_MESH_SIMPLE; // r=0.5, halfHeight=0.5 (total h=2.0)
```
The long axis is always Y. This mirrors the physics capsule body (see
`.claude/physics.md`).
### Triangular prism (`triprism.h`)
```c
#define TRIPRISM_VERTEX_COUNT 24
// Cross-section triangle defined by three 2D points in XY;
// extruded along Z from minZ to maxZ.
void triPrismBuffer(
meshvertex_t *vertices,
const float_t x0, const float_t y0,
const float_t x1, const float_t y1,
const float_t x2, const float_t y2,
const float_t minZ, const float_t maxZ
);
extern mesh_t TRIPRISM_MESH_SIMPLE;
// Unit prism: triangle (0,0),(1,0),(0.5,1) extruded z=0 to z=1.
```
---
## Custom dynamic mesh
If you need to update geometry each frame (e.g. a procedural mesh):
```c
static meshvertex_t myVerts[MY_VERT_COUNT];
static mesh_t myMesh;
// On init:
// Fill myVerts, then:
errorChain(meshInit(&myMesh, MESH_PRIMITIVE_TYPE_TRIANGLES,
MY_VERT_COUNT, myVerts));
// Each frame (after modifying myVerts):
errorChain(meshFlush(&myMesh, 0, -1));
errorChain(meshDraw(&myMesh, 0, -1));
```
---
## Notes
- `meshInit` must be called on the **main thread** (GPU upload).
- `meshFlush` is required on OpenGL targets when vertices change
after init. It is a no-op on Dolphin.
- All `_MESH_SIMPLE` globals are initialised during engine startup --
do not call `meshInit` on them manually.
+133
View File
@@ -0,0 +1,133 @@
# Display -- SpriteBatch
Source: `src/dusk/display/spritebatch/`
See also: `.claude/display-mesh.md`, `.claude/display-texture.md`
---
## Overview
The SpriteBatch is the primary 2D rendering primitive. It accumulates
axis-aligned quads (sprites) into a shared vertex buffer and draws them
in batches. All 2D rendering in the engine -- UI frames, text, tilemaps,
HUD -- goes through the global `SPRITEBATCH`.
The batch flushes automatically when the per-flush limit is reached, or
explicitly via `spriteBatchFlush()`.
---
## Limits
| Constant | Value | Meaning |
|----------|-------|---------|
| `SPRITEBATCH_SPRITES_MAX` | 512 | Total sprites in the vertex buffer |
| `SPRITEBATCH_FLUSH_COUNT` | 16 | Number of auto-flush segments |
| `SPRITEBATCH_SPRITES_MAX_PER_FLUSH` | 32 | Sprites per auto-flush segment |
| `SPRITEBATCH_VERTEX_COUNT` | 3072 | Total vertices (512 * QUAD_VERTEX_COUNT) |
---
## Sprite structure
```c
typedef struct {
vec3 min; // minimum XYZ corner of the quad in world/screen space
vec3 max; // maximum XYZ corner of the quad in world/screen space
vec2 uvMin; // minimum UV (top-left in [0,1] texture space)
vec2 uvMax; // maximum UV (bottom-right in [0,1] texture space)
} spritebatchsprite_t;
```
Z in `min` and `max` controls draw depth (further from camera = higher Z
in a typical orthographic setup). For flat 2D, set `min.z = max.z = 0`.
---
## SpriteBatch struct
```c
typedef struct {
mesh_t mesh;
int32_t spriteCount;
int32_t spriteFlush;
shader_t *shader;
shadermaterial_t material;
} spritebatch_t;
extern spritebatch_t SPRITEBATCH;
extern meshvertex_t SPRITEBATCH_VERTICES[SPRITEBATCH_VERTEX_COUNT];
```
`SPRITEBATCH_VERTICES` is a separate global (not embedded in the struct)
for platform alignment requirements.
---
## API
```c
errorret_t spriteBatchInit();
errorret_t spriteBatchDispose();
// Clear the buffer and reset state. Call before starting a new batch.
void spriteBatchClear();
// Append sprites to the buffer. Flushes automatically when the per-flush
// segment fills. shader + material are used on the next flush.
errorret_t spriteBatchBuffer(
const spritebatchsprite_t *sprites,
const uint32_t count,
shader_t *shader,
const shadermaterial_t material
);
// Upload and draw all buffered sprites. Binds shader and applies
// material if set. No-op if the buffer is empty.
errorret_t spriteBatchFlush();
```
---
## Typical usage
```c
// Beginning of a 2D render pass:
spriteBatchClear();
// Build sprites (e.g. via tilesetTileGetUV, then fill spritebatchsprite_t):
spritebatchsprite_t s;
glm_vec3_copy((vec3){ x, y, 0 }, s.min);
glm_vec3_copy((vec3){ x + w, y + h, 0 }, s.max);
glm_vec2_copy(uvMin, s.uvMin);
glm_vec2_copy(uvMax, s.uvMax);
shadermaterial_t mat = { .unlit = { .texture = myTexture } };
spriteBatchBuffer(&s, 1, myShader, mat);
// End of pass -- flush remaining sprites:
spriteBatchFlush();
```
---
## Relationship to other systems
- **Text rendering** (`textDraw`) internally calls `spriteBatchBuffer`
for each glyph and requires a final `spriteBatchFlush()` after drawing.
- **UI frames** (`uiFrameDraw`) push 9 quads to the batch without
flushing -- the caller or `uitextboxDraw` is responsible for the flush.
- **ECS renderables** of type `ENTITY_RENDERABLE_TYPE_SPRITEBATCH` are
drawn via the spritebatch in the scene render pipeline.
---
## Notes
- `spriteBatchBuffer` changes the batch's `shader` and `material` fields.
If you mix different shaders or textures in one batch, add an explicit
`spriteBatchFlush()` call between groups to avoid draws with the wrong
material.
- The vertex buffer is a static global -- `SPRITEBATCH_VERTICES` must
not be written from multiple threads.
+115
View File
@@ -0,0 +1,115 @@
# Display -- Text Rendering
Source: `src/dusk/display/text/`
See also: `.claude/display-spritebatch.md`, `.claude/display-texture.md`
---
## Overview
Text rendering is layered on top of the SpriteBatch. Each character
maps to a glyph tile in a bitmap font atlas; `textDraw` builds the
corresponding `spritebatchsprite_t` values and pushes them to the
global `SPRITEBATCH`. The caller is responsible for flushing the batch.
---
## Font type (`font.h`)
```c
typedef struct {
texture_t *texture; // glyph atlas texture
tileset_t *tileset; // grid describing glyph size + UV layout
} font_t;
```
Both pointers are caller-owned. The text system does not allocate or
free them.
```c
extern font_t FONT_DEFAULT;
```
`FONT_DEFAULT` is the engine's built-in bitmap font. It is initialised
during `textInit()` and available for the engine lifetime.
---
## Character range
```c
#define TEXT_CHAR_START '!' // ASCII 33
```
The glyph atlas begins at `'!'` (ASCII 33). Characters below this value
-- space, control characters -- are handled specially:
- `' '` (space) advances the cursor by one tile width without drawing.
- Characters below `TEXT_CHAR_START` other than space are skipped.
---
## API (`text.h`)
```c
// Initialises the text system and FONT_DEFAULT.
errorret_t textInit(void);
// Disposes of the text system.
errorret_t textDispose(void);
// Draw a null-terminated string at (x, y) in screen/world space.
// Pushes sprites to SPRITEBATCH. Caller must call spriteBatchFlush()
// after all text has been drawn.
errorret_t textDraw(
const float_t x,
const float_t y,
const char_t *text,
const color_t color,
font_t *font
);
// Measure the bounding box of a string without drawing it.
void textMeasure(
const char_t *text,
const font_t *font,
int32_t *outWidth,
int32_t *outHeight
);
// Low-level: build a single glyph sprite at position pos.
// Returns a spritebatchsprite_t ready for spriteBatchBuffer.
spritebatchsprite_t textGetSprite(
const vec2 pos,
const char_t c,
const font_t *font
);
```
---
## Typical usage
```c
// Inside a render callback:
errorChain(textDraw(10.0f, 10.0f, "Hello", COLOR_WHITE, &FONT_DEFAULT));
errorChain(spriteBatchFlush());
```
If you are also drawing UI frames or other sprites in the same pass,
batch all the `textDraw` and `spriteBatchBuffer` calls first, then call
`spriteBatchFlush()` once at the end.
---
## Notes
- Text coordinates are in the same space as the scene render (screen
space for UI, or world space if placed in the scene).
- `textMeasure` returns pixel dimensions based on the font's
`tileset.tileWidth` and `tileset.tileHeight`. Use it to centre or
right-align text before drawing.
- For UI-attached text (dialogue, labels), prefer the `uitextbox_t`
system which handles word-wrap and paging automatically
(see `.claude/ui.md`).
+4
View File
@@ -17,3 +17,7 @@ Dolphin (GX) implementation in `src/duskdolphin/`.
| Screen size modes, framebuffer, screen | `.claude/display-core.md` | | Screen size modes, framebuffer, screen | `.claude/display-core.md` |
| Texture, tileset, font | `.claude/display-texture.md` | | Texture, tileset, font | `.claude/display-texture.md` |
| Shader, shader material, display state | `.claude/display-shader.md` | | Shader, shader material, display state | `.claude/display-shader.md` |
| Mesh, vertex format, primitive generators | `.claude/display-mesh.md` |
| SpriteBatch (2D quad renderer) | `.claude/display-spritebatch.md` |
| Text rendering, font, FONT_DEFAULT | `.claude/display-text.md` |
| Color types, macros, named constants | `.claude/display-color.md` |
+226
View File
@@ -0,0 +1,226 @@
# 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.
+6
View File
@@ -65,6 +65,12 @@ Detailed documentation on specific topics lives in `.claude/`:
| Display -- screen, framebuffer, size modes | `.claude/display-core.md` | | Display -- screen, framebuffer, size modes | `.claude/display-core.md` |
| Display -- texture, tileset, font | `.claude/display-texture.md` | | Display -- texture, tileset, font | `.claude/display-texture.md` |
| Display -- shader, material, display state | `.claude/display-shader.md` | | Display -- shader, material, display state | `.claude/display-shader.md` |
| Display -- mesh, vertex format, primitives | `.claude/display-mesh.md` |
| Display -- SpriteBatch (2D quad renderer) | `.claude/display-spritebatch.md` |
| Display -- text rendering, FONT_DEFAULT | `.claude/display-text.md` |
| Display -- color types, macros, constants | `.claude/display-color.md` |
| UI system (frame, textbox, fullbox, loading, FPS) | `.claude/ui.md` |
| Console (debug overlay, POSIX stdin mode) | `.claude/console.md` |
| Scene system (lifecycle, render pipeline, JS hooks) | `.claude/scene.md` | | Scene system (lifecycle, render pipeline, JS hooks) | `.claude/scene.md` |
--- ---