Add the manual: nineteen chapters and a corrected README
docs/ is a narrative manual, not a second reference. Every header already
carries a substantial @file/@brief block and Doxyfile sets WARN_IF_UNDOCUMENTED
with WARN_AS_ERROR, so an undocumented symbol already fails CI. The gap was
navigation and worked examples. Chapters teach a task and link to the Doxygen
output; where a declaration or a constant table has to be in front of the
reader it arrives as a `c excerpt=` block, so the text *is* the header and
cannot diverge from it. That also preserves the hand-aligned bit-flag tables
scripts/reindent.el goes out of its way not to destroy.
The manual does not re-document its dependencies. libakerror owns the
ATTEMPT/CLEANUP/PROCESS/HANDLE/FINISH protocol, SDL3 owns renderers and events,
Tiled owns the map format, jansson owns json_t. A chapter that restated any of
them would be wrong the day upstream changed and nothing here would notice --
the same drift this work exists to fix, arriving from a different direction. So
each chapter says what libakgl adds or constrains and links out for the rest.
Chapter 4 is the exception and the reason for it: libakerror documents the
mechanism, but only libakgl can say which statuses its own functions raise and
what they mean here, and that was written down nowhere. It carries three tables
-- libakgl's five status codes, the libakerror statuses libakgl actually raises
with their meaning in this library, and the exit-status trap where
`exit(AKGL_ERR_SDL)` is a wait status of 0 because the band starts at 256.
Every chapter was written against src/ rather than against the header comments,
which is how 27 false claims in those comments came to light. Where a chapter
documents a known defect rather than a design decision it says so and points at
TODO.md.
README.md keeps the development process and hands the reader to docs/. Its
task-oriented FAQ is deleted rather than moved, because one source of truth per
topic is the whole point and that FAQ's examples did not compile.
Census: 39 compiled snippets, 89 verbatim header excerpts, 4 JSON documents run
through the real loaders, one linked-and-executed program with its output
compared byte for byte, one generated figure. 11 norun blocks, each justified.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 20:58:37 -04:00
|
|
|
# The libakgl manual
|
|
|
|
|
|
|
|
|
|
libakgl is a C library for building 2D games on SDL3. It is not an engine: there is no
|
|
|
|
|
editor, no scripting layer, no inheritance and no runtime `malloc`. Behaviour attaches to a
|
|
|
|
|
struct as function pointers, objects come from fixed pools, and every call reports failure
|
|
|
|
|
through an error context you cannot silently ignore.
|
|
|
|
|
|
|
|
|
|
This manual teaches the library. It deliberately does **not** re-document its dependencies
|
|
|
|
|
— libakerror owns the error-handling protocol, SDL3 owns renderers and events, Tiled owns
|
|
|
|
|
the map format, jansson owns the JSON API. Each chapter says what libakgl adds or
|
|
|
|
|
constrains, shows what a caller actually writes, and links out for the rest. For
|
|
|
|
|
per-function reference, build the Doxygen output with `doxygen Doxyfile`.
|
|
|
|
|
|
|
|
|
|
| | |
|
|
|
|
|
|---|---|
|
|
|
|
|
| **[1. Introduction](01-introduction.md)** | What libakgl is, what it refuses to be, the frame budget, and who owns which documentation |
|
|
|
|
|
| **[2. Design philosophy](02-design-philosophy.md)** | Bounded pools, pluggable backends, bit flags, name-based registries, one world at a time |
|
|
|
|
|
| **[3. Getting started](03-getting-started.md)** | Dependencies, `add_subdirectory` vs `akgl.pc`, and the smallest program that opens a window |
|
|
|
|
|
| **[4. Errors and status codes](04-errors.md)** | The status tables, what each code means *here*, and the traps that fail silently |
|
Document collision, and correct what it made false elsewhere
The new chapter 15 covers the opt-in setup, where resolution runs in the step
and why it runs after the move, shapes and the z-extrusion trap, the asymmetric
masks and the defaults that matter more than the mechanism, tiles as a source
rather than proxies, the response hook and the three ways it is easy to write
wrongly, sensors, the four queries, both partitioners, and what is still not
implemented.
Collision falsified claims in eight other chapters. The physics chapter said
"There is no collision detection, at all" and that collide always raises
AKERR_API; actors had six behaviour hooks; the heap had five pools and four
non-claiming acquires; the status band held five codes; and the design
philosophy had exactly two pluggable subsystems. The appendix gains a
collision.h status section, the three new pool ceilings and a table of the
collision constants that are deliberately not in a public header.
Also fixes chapter labels the renumbering commit left pointing at their old
numbers -- "18. Utilities" linked to 19-utilities.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzBDV2fqgnUAcqCKqKvc71
2026-08-02 07:25:52 -04:00
|
|
|
| **[5. The heap](05-the-heap.md)** | The eight pools, `akgl_heap_next_*`, `akgl_String`, and why exhaustion usually means a missing release |
|
Add the manual: nineteen chapters and a corrected README
docs/ is a narrative manual, not a second reference. Every header already
carries a substantial @file/@brief block and Doxyfile sets WARN_IF_UNDOCUMENTED
with WARN_AS_ERROR, so an undocumented symbol already fails CI. The gap was
navigation and worked examples. Chapters teach a task and link to the Doxygen
output; where a declaration or a constant table has to be in front of the
reader it arrives as a `c excerpt=` block, so the text *is* the header and
cannot diverge from it. That also preserves the hand-aligned bit-flag tables
scripts/reindent.el goes out of its way not to destroy.
The manual does not re-document its dependencies. libakerror owns the
ATTEMPT/CLEANUP/PROCESS/HANDLE/FINISH protocol, SDL3 owns renderers and events,
Tiled owns the map format, jansson owns json_t. A chapter that restated any of
them would be wrong the day upstream changed and nothing here would notice --
the same drift this work exists to fix, arriving from a different direction. So
each chapter says what libakgl adds or constrains and links out for the rest.
Chapter 4 is the exception and the reason for it: libakerror documents the
mechanism, but only libakgl can say which statuses its own functions raise and
what they mean here, and that was written down nowhere. It carries three tables
-- libakgl's five status codes, the libakerror statuses libakgl actually raises
with their meaning in this library, and the exit-status trap where
`exit(AKGL_ERR_SDL)` is a wait status of 0 because the band starts at 256.
Every chapter was written against src/ rather than against the header comments,
which is how 27 false claims in those comments came to light. Where a chapter
documents a known defect rather than a design decision it says so and points at
TODO.md.
README.md keeps the development process and hands the reader to docs/. Its
task-oriented FAQ is deleted rather than moved, because one source of truth per
topic is the whole point and that FAQ's examples did not compile.
Census: 39 compiled snippets, 89 verbatim header excerpts, 4 JSON documents run
through the real loaders, one linked-and-executed program with its output
compared byte for byte, one generated figure. 11 norun blocks, each justified.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 20:58:37 -04:00
|
|
|
| **[6. The registry](06-the-registry.md)** | The eight registries, configuration properties, and the id-0 silent no-op |
|
|
|
|
|
| **[7. The game and the frame](07-the-game-and-the-frame.md)** | Startup order, `akgl_game_update`, the state lock, iterators, savegames |
|
|
|
|
|
| **[8. Rendering](08-rendering.md)** | The backend vtable, the frame contract, cameras, and embedding a host's own `SDL_Renderer` |
|
|
|
|
|
| **[9. Drawing](09-drawing.md)** | Points, lines, rectangles, circles, flood fill, and saving a region |
|
|
|
|
|
| **[10. Spritesheets and sprites](10-spritesheets-and-sprites.md)** | One texture shared by path, the sprite JSON format, frame animation |
|
|
|
|
|
| **[11. Characters](11-characters.md)** | State-to-sprite mappings, movement constants, the character JSON format |
|
Document collision, and correct what it made false elsewhere
The new chapter 15 covers the opt-in setup, where resolution runs in the step
and why it runs after the move, shapes and the z-extrusion trap, the asymmetric
masks and the defaults that matter more than the mechanism, tiles as a source
rather than proxies, the response hook and the three ways it is easy to write
wrongly, sensors, the four queries, both partitioners, and what is still not
implemented.
Collision falsified claims in eight other chapters. The physics chapter said
"There is no collision detection, at all" and that collide always raises
AKERR_API; actors had six behaviour hooks; the heap had five pools and four
non-claiming acquires; the status band held five codes; and the design
philosophy had exactly two pluggable subsystems. The appendix gains a
collision.h status section, the three new pool ceilings and a table of the
collision constants that are deliberately not in a public header.
Also fixes chapter labels the renumbering commit left pointing at their old
numbers -- "18. Utilities" linked to 19-utilities.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzBDV2fqgnUAcqCKqKvc71
2026-08-02 07:25:52 -04:00
|
|
|
| **[12. Actors](12-actors.md)** | The state bitmask, the seven behaviour hooks, parents and children, layers |
|
Add the manual: nineteen chapters and a corrected README
docs/ is a narrative manual, not a second reference. Every header already
carries a substantial @file/@brief block and Doxyfile sets WARN_IF_UNDOCUMENTED
with WARN_AS_ERROR, so an undocumented symbol already fails CI. The gap was
navigation and worked examples. Chapters teach a task and link to the Doxygen
output; where a declaration or a constant table has to be in front of the
reader it arrives as a `c excerpt=` block, so the text *is* the header and
cannot diverge from it. That also preserves the hand-aligned bit-flag tables
scripts/reindent.el goes out of its way not to destroy.
The manual does not re-document its dependencies. libakerror owns the
ATTEMPT/CLEANUP/PROCESS/HANDLE/FINISH protocol, SDL3 owns renderers and events,
Tiled owns the map format, jansson owns json_t. A chapter that restated any of
them would be wrong the day upstream changed and nothing here would notice --
the same drift this work exists to fix, arriving from a different direction. So
each chapter says what libakgl adds or constrains and links out for the rest.
Chapter 4 is the exception and the reason for it: libakerror documents the
mechanism, but only libakgl can say which statuses its own functions raise and
what they mean here, and that was written down nowhere. It carries three tables
-- libakgl's five status codes, the libakerror statuses libakgl actually raises
with their meaning in this library, and the exit-status trap where
`exit(AKGL_ERR_SDL)` is a wait status of 0 because the band starts at 256.
Every chapter was written against src/ rather than against the header comments,
which is how 27 false claims in those comments came to light. Where a chapter
documents a known defect rather than a design decision it says so and points at
TODO.md.
README.md keeps the development process and hands the reader to docs/. Its
task-oriented FAQ is deleted rather than moved, because one source of truth per
topic is the whole point and that FAQ's examples did not compile.
Census: 39 compiled snippets, 89 verbatim header excerpts, 4 JSON documents run
through the real loaders, one linked-and-executed program with its output
compared byte for byte, one generated figure. 11 norun blocks, each justified.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 20:58:37 -04:00
|
|
|
| **[13. Tilemaps](13-tilemaps.md)** | Tiled TMJ, libakgl's three extensions, and the limits that bind a map |
|
|
|
|
|
| **[14. Physics](14-physics.md)** | Thrust, environment and velocity; the `null` and `arcade` backends; what is not implemented |
|
Document collision, and correct what it made false elsewhere
The new chapter 15 covers the opt-in setup, where resolution runs in the step
and why it runs after the move, shapes and the z-extrusion trap, the asymmetric
masks and the defaults that matter more than the mechanism, tiles as a source
rather than proxies, the response hook and the three ways it is easy to write
wrongly, sensors, the four queries, both partitioners, and what is still not
implemented.
Collision falsified claims in eight other chapters. The physics chapter said
"There is no collision detection, at all" and that collide always raises
AKERR_API; actors had six behaviour hooks; the heap had five pools and four
non-claiming acquires; the status band held five codes; and the design
philosophy had exactly two pluggable subsystems. The appendix gains a
collision.h status section, the three new pool ceilings and a table of the
collision constants that are deliberately not in a public header.
Also fixes chapter labels the renumbering commit left pointing at their old
numbers -- "18. Utilities" linked to 19-utilities.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzBDV2fqgnUAcqCKqKvc71
2026-08-02 07:25:52 -04:00
|
|
|
| **[15. Collision](15-collision.md)** | Shapes, masks, tiles as geometry, the response hook, and the two partitioners |
|
|
|
|
|
| **[16. Input](16-input.md)** | Control maps, push-not-poll dispatch, the keystroke ring, gamepads |
|
|
|
|
|
| **[17. Text and fonts](17-text-and-fonts.md)** | Loading, drawing, measuring, and the teardown order that matters |
|
|
|
|
|
| **[18. Audio](18-audio.md)** | The three-voice synthesizer, and the separate background-music path |
|
|
|
|
|
| **[19. Utilities](19-utilities.md)** | Rectangle overlap, path resolution, the JSON accessors, static strings |
|
|
|
|
|
| **[20. Tutorial: a 2D sidescroller](20-tutorial-sidescroller.md)** | Gravity, a jump, collision, coins and hazards |
|
|
|
|
|
| **[21. Tutorial: a top-down JRPG](21-tutorial-jrpg.md)** | A town map, NPCs spawned from map objects, four-way animation, a text box, a follower |
|
|
|
|
|
| **[22. Appendix](22-appendix-limits.md)** | Every limit, every status, every configuration property |
|
Add the manual: nineteen chapters and a corrected README
docs/ is a narrative manual, not a second reference. Every header already
carries a substantial @file/@brief block and Doxyfile sets WARN_IF_UNDOCUMENTED
with WARN_AS_ERROR, so an undocumented symbol already fails CI. The gap was
navigation and worked examples. Chapters teach a task and link to the Doxygen
output; where a declaration or a constant table has to be in front of the
reader it arrives as a `c excerpt=` block, so the text *is* the header and
cannot diverge from it. That also preserves the hand-aligned bit-flag tables
scripts/reindent.el goes out of its way not to destroy.
The manual does not re-document its dependencies. libakerror owns the
ATTEMPT/CLEANUP/PROCESS/HANDLE/FINISH protocol, SDL3 owns renderers and events,
Tiled owns the map format, jansson owns json_t. A chapter that restated any of
them would be wrong the day upstream changed and nothing here would notice --
the same drift this work exists to fix, arriving from a different direction. So
each chapter says what libakgl adds or constrains and links out for the rest.
Chapter 4 is the exception and the reason for it: libakerror documents the
mechanism, but only libakgl can say which statuses its own functions raise and
what they mean here, and that was written down nowhere. It carries three tables
-- libakgl's five status codes, the libakerror statuses libakgl actually raises
with their meaning in this library, and the exit-status trap where
`exit(AKGL_ERR_SDL)` is a wait status of 0 because the band starts at 256.
Every chapter was written against src/ rather than against the header comments,
which is how 27 false claims in those comments came to light. Where a chapter
documents a known defect rather than a design decision it says so and points at
TODO.md.
README.md keeps the development process and hands the reader to docs/. Its
task-oriented FAQ is deleted rather than moved, because one source of truth per
topic is the whole point and that FAQ's examples did not compile.
Census: 39 compiled snippets, 89 verbatim header excerpts, 4 JSON documents run
through the real loaders, one linked-and-executed program with its output
compared byte for byte, one generated figure. 11 norun blocks, each justified.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 20:58:37 -04:00
|
|
|
|
|
|
|
|
Both tutorials are complete programs under [`examples/`](../examples). They build with the
|
|
|
|
|
library and run headless in CI, and the chapters quote them rather than restating them — so
|
|
|
|
|
a tutorial cannot drift from a program that compiles.
|
|
|
|
|
|
|
|
|
|
## Every example here is checked
|
|
|
|
|
|
|
|
|
|
The examples in these chapters are compiled, linked, run, and cross-checked against the
|
|
|
|
|
source tree by the test suite. A snippet that stops compiling, an excerpt that no longer
|
|
|
|
|
matches the header it quotes, or a JSON document the loader would reject turns
|
|
|
|
|
`ctest -R docs_examples` red.
|
|
|
|
|
|
|
|
|
|
This exists because the documentation it replaces had drifted badly: the previous FAQ's
|
|
|
|
|
examples did not compile — two unbalanced `PASS()` calls, a `sprite->frameids = [0, 1, 2, 3];`
|
|
|
|
|
that is not C in any dialect, and, in the first snippet a reader ever saw, the exact
|
|
|
|
|
`strncpy` call `AGENTS.md` forbids. The prose had drifted with it, and writing these
|
|
|
|
|
chapters turned up **twenty-seven** header claims that were false against `src/`.
|
|
|
|
|
|
|
|
|
|
Where a chapter documents behaviour that is a known defect rather than a design decision,
|
|
|
|
|
it says so and points at `TODO.md`. See `MAINTENANCE.md` if you are editing an example.
|
|
|
|
|
|
|
|
|
|
## Assets
|
|
|
|
|
|
|
|
|
|
The tutorial art, tiles and music are CC0, vendored under
|
|
|
|
|
[`tutorials/assets/`](tutorials/assets) with provenance recorded per file in
|
|
|
|
|
[`PROVENANCE.md`](tutorials/assets/PROVENANCE.md) and geometry documented in
|
|
|
|
|
[`README.md`](tutorials/assets/README.md). CC0 specifically, not merely free: a reader who
|
|
|
|
|
copies a tutorial into their own game inherits no obligation.
|