Host API¶
The host implements citsy::Host — a C++ analogue of the bitsy global object from the Bitsy System API. The engine calls into the host for input and time; the host reads memory blocks and audio state that the engine owns.
Headers: include/citsy/host.hpp, include/citsy/types.hpp.
Constants¶
| Name | Value | Meaning |
|---|---|---|
kTileSize |
8 | Pixels per tile edge |
kMapSize |
16 | Room width/height in tiles |
kVideoSize |
128 | Main framebuffer edge in pixels (16 × 8) |
| Enumerator | Meaning |
|---|---|
GraphicsMode::Video |
Direct per-pixel framebuffer |
GraphicsMode::Map |
Tilemap mode (normal gameplay) |
TextMode::HiRez |
Textbox at 2× pixel scale |
TextMode::LoRez |
Textbox at 4× pixel scale |
Buttons¶
| Code | Action |
|---|---|
Up |
Move avatar / menu up |
Down |
Move avatar / menu down |
Left |
Move avatar / menu left |
Right |
Move avatar / menu right |
Ok |
Interact, advance dialog |
Menu |
Pause / restart (host-defined) |
The host normalizes keyboard, gamepad, and touch into these six logical buttons.
Memory blocks¶
The engine maintains fixed logical buffers. The host reads them after each update; the engine may resize the textbox buffer when dialog layout changes.
| Block | Size (typical) | Purpose |
|---|---|---|
Video |
128 × 128 | Per-pixel color indices in GraphicsMode::Video |
Textbox |
w × h (dynamic) | Dialog text rendered as color indices |
Map1 |
16 × 16 | Primary tilemap (tile IDs) |
Map2 |
16 × 16 | Overlay tilemap (sprites / items) |
Sound1, Sound2 |
— | Channel frequency, volume, pulse, duration |
Color indices refer to the active palette passed into present(). Hosts should not assume a fixed 3-color palette — extended palettes (COL n) are supported.
Interface¶
class Host {
public:
virtual ~Host() = default;
virtual void on_engine_ready() {}
virtual double delta_time_ms() const = 0;
virtual bool button(Button code) const = 0;
virtual void log(std::string_view message) {}
virtual void present(
GraphicsMode gfx_mode,
TextMode txt_mode,
std::span<const Color> palette,
std::span<const std::uint8_t> video, // 128×128 indices
std::span<const std::uint8_t> map1, // 16×16 tile IDs
std::span<const std::uint8_t> map2,
TextboxView textbox, // may be hidden
SoundChannel sound1,
SoundChannel sound2
) = 0;
};
| Method | Direction | Purpose |
|---|---|---|
delta_time_ms() |
host → engine | Frame delta in milliseconds |
button(Button) |
host → engine | Logical button held-state |
on_engine_ready() |
engine → host | Once after Engine::start() |
log(message) |
engine → host | Optional diagnostic sink |
present(...) |
engine → host | Full frame state after each update() |
TextboxView¶
| Field | Meaning |
|---|---|
visible |
Whether the dialog box should be drawn |
x, y |
Top-left in 128×128 Bitsy units |
width, height |
Pixel size of pixels |
pixels |
Color indices; empty when not visible |
SoundChannel¶
| Field | Meaning |
|---|---|
active |
Host should play this channel |
duration_ms |
Remaining note / blip time |
frequency_hz |
Square-wave frequency |
volume |
0.0 – 1.0 |
pulse |
Duty cycle: Eighth, Quarter, or Half |
The engine never generates PCM. The host synthesizes two pulse waves (or ignores them).
Graphics modes¶
GraphicsMode::Map— Default gameplay. Compose the room from tile IDs inmap1, then sprites and items frommap2.GraphicsMode::Video— Transitions and effects. Read individual pixel color indices fromvideo.
Switch on the gfx_mode argument to present(). The unused buffer is still passed; ignore it.
Palette updates¶
When a game or transition changes colors, the engine updates its internal palette and passes the full RGB table to present(). Index 0 is background, 1 is tile, 2 is sprite; further indices are extended palette colors.
Backends¶
| Backend | Status | Use case |
|---|---|---|
| MockHost | Implemented | Unit tests; records PresentSnapshot per frame |
| raylib | Planned | Reference desktop player with window and audio |
| 32blit | Planned | Handheld device backend |
MockHost is header-only (backends/mock/mock_host.hpp). It stores every present() call so tests can assert on buffer sizes, palette colors, and graphics mode without a display. See Testing.
Implementing present()¶
- raylib — Upload indices to a 128×128
Image/Texture, scale with integer nearest-neighbor, mix square-wave audio. - 32blit — Blit directly into the handheld framebuffer at native resolution.
- MockHost — Record snapshots; no window.
Keep platform code out of core
The citsy library must not link raylib, SDL, OpenGL, or any audio/window library. Backends live under backends/ as optional CMake targets.