Compile, link and run every example in the documentation
libakgl exports 157 functions and the only user-facing documentation was a FAQ
in README.md whose examples did not compile: two unbalanced `PASS()` calls, a
`sprite->frameids = [0, 1, 2, 3];` that is not C in any dialect, a stray `9`
inside a bitmask expression, an `int screenwidth = NULL`, and -- in the first
snippet a reader ever saw -- the exact `strncpy` call AGENTS.md forbids.
That is not a reader routing around typos. It is what happens to samples that
nothing executes. This is akbasic's documentation harness with the interpreter
taken out and the ability to link and run put in.
The contract is a set of fence info strings, so an example is ordinary markdown
that still highlights on the forge:
```c compiled with -fsyntax-only -Wall -Werror
```c wrap=NAME the same, wrapped in tests/docs_preludes/NAME.pre/.post
```c run=NAME linked against akgl and run headless
```c excerpt=PATH must still appear verbatim in PATH
```c screenshot=NAME also the source of docs/images/NAME.png
```json kind=KIND loaded through the real akgl_*_load_json
```output the exact stdout of the runnable block above it
`run=` is why this links at all: -fsyntax-only proves a call typechecks, not
that the startup order works or that an ATTEMPT block gives back what it took.
`json kind=` exists because the asset formats are documented in prose and read
by four loaders with nothing tying the two together -- util/assets/littleguy.json
is already invalid against the loader it ships with.
A fence with no info string is a hard error, and so is an unknown one. The
failure mode this exists to prevent is passing because it quietly ran nothing,
so an unannotated block is a missing decision rather than a default. Exit status
is the number of failed examples; 2 for a usage error, which is a different
thing and has to be distinguishable.
Proven to fail on all ten of its failure modes -- untagged fence, non-compiling
snippet, stale excerpt, orphan output block, unknown info string, run= output
mismatch, invalid JSON, missing figure, a -Werror warning, and a dangling
preload= -- because a check that has never failed has not been tested.
`-Werror` here although AKGL_WERROR stays off for the library: that option is
off so a new compiler's diagnostic cannot break a consumer's build, and a doc
snippet is not a consumer. A sample that warns is a sample that teaches the
warning.
Registered as `docs_examples` and `docs_screenshots`. No docs-path filter in CI,
deliberately: documentation goes stale because the code moved, not because
somebody edited a chapter.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 20:58:11 -04:00
|
|
|
/**
|
|
|
|
|
* @file docs_prelude.h
|
|
|
|
|
* @brief The include set every `c wrap=`, `c run=` and `c screenshot=` block gets.
|
|
|
|
|
*
|
|
|
|
|
* The four preludes in this directory all begin with this file, so the list of
|
|
|
|
|
* headers a wrapped example can rely on lives in exactly one place. It is not
|
|
|
|
|
* reachable from a `c` block with no `wrap=`: an unwrapped block is a whole
|
|
|
|
|
* translation unit and has to show its own `#include` lines, which is usually
|
|
|
|
|
* what a chapter wants a reader to see.
|
|
|
|
|
*
|
|
|
|
|
* Every public header, deliberately. The `headers` suite already proves each one
|
|
|
|
|
* is self-contained, so there is no ordering to get right, and an example that
|
|
|
|
|
* calls one subsystem while illustrating another does not have to grow an
|
|
|
|
|
* include line that is noise in the chapter.
|
|
|
|
|
*
|
|
|
|
|
* `docs_frame()` is declared here rather than in tools/docs_screenshot.c so the
|
|
|
|
|
* host and the akglframe prelude cannot drift apart on the signature.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef _AKGL_DOCS_PRELUDE_H_
|
|
|
|
|
#define _AKGL_DOCS_PRELUDE_H_
|
|
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
|
#include <SDL3_image/SDL_image.h>
|
|
|
|
|
|
|
|
|
|
#include <akerror.h>
|
|
|
|
|
#include <akstdlib.h>
|
|
|
|
|
|
|
|
|
|
#include <akgl/actor.h>
|
|
|
|
|
#include <akgl/assets.h>
|
|
|
|
|
#include <akgl/audio.h>
|
|
|
|
|
#include <akgl/character.h>
|
|
|
|
|
#include <akgl/controller.h>
|
|
|
|
|
#include <akgl/draw.h>
|
|
|
|
|
#include <akgl/error.h>
|
|
|
|
|
#include <akgl/game.h>
|
|
|
|
|
#include <akgl/heap.h>
|
|
|
|
|
#include <akgl/iterator.h>
|
|
|
|
|
#include <akgl/json_helpers.h>
|
|
|
|
|
#include <akgl/physics.h>
|
|
|
|
|
#include <akgl/registry.h>
|
|
|
|
|
#include <akgl/renderer.h>
|
|
|
|
|
#include <akgl/sprite.h>
|
|
|
|
|
#include <akgl/staticstring.h>
|
|
|
|
|
#include <akgl/text.h>
|
|
|
|
|
#include <akgl/tilemap.h>
|
|
|
|
|
#include <akgl/types.h>
|
Vendor clay and bring the UI subsystem up: arena, lifecycle, status band
clay v0.14 (deps/clay, zlib licence) supplies the layout engine for the new
akgl_ui subsystem. Sources-listed rather than add_subdirectory()'d, on the
semver/libccd precedent: clay's CMakeLists declares no library target, builds
its examples by default, and requires CMake 3.27 against this project's 3.10.
src/ui_clay.c is the one CLAY_IMPLEMENTATION translation unit, compiled -w on
the vendored-code terms but with clay's symbols deliberately exported --
consumers' CLAY() macros resolve against libakgl.so, and akgl/ui.h warns them
never to link a second clay.
The subsystem is runtime-optional the way collision is: always compiled in,
inert until akgl_ui_init(), which bounds clay to the overridable AKGL_UI_*
ceilings, checks Clay_MinMemorySize() against a static BSS arena (no malloc),
and refuses with both numbers in the message when it does not fit. Measured:
812544 bytes at the default 1024 elements / 4096 measured words, against a
1 MiB arena. clay's void-callback layout errors are logged as they happen and
the first is stashed for the error protocol to raise later.
AKGL_ERR_UI joins the status band before AKGL_ERR_LIMIT, named in
akgl_error_init. New `ui` test suite covers validation, the init/shutdown
lifecycle, and arena exhaustion via the akgl_ui_arena_limit test hook (same
contract as akgl_ccd_arena_set_limit). clay.h is installed beside semver.h,
its licence beside libccd's, and the headers suite proves akgl/ui.h
self-contained -- clay.h compiles clean under -Wall.
Co-Authored-By: Claude Code (Claude Fable 5, claude-fable-5) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KzBDV2fqgnUAcqCKqKvc71
2026-08-02 10:53:11 -04:00
|
|
|
#include <akgl/ui.h>
|
Compile, link and run every example in the documentation
libakgl exports 157 functions and the only user-facing documentation was a FAQ
in README.md whose examples did not compile: two unbalanced `PASS()` calls, a
`sprite->frameids = [0, 1, 2, 3];` that is not C in any dialect, a stray `9`
inside a bitmask expression, an `int screenwidth = NULL`, and -- in the first
snippet a reader ever saw -- the exact `strncpy` call AGENTS.md forbids.
That is not a reader routing around typos. It is what happens to samples that
nothing executes. This is akbasic's documentation harness with the interpreter
taken out and the ability to link and run put in.
The contract is a set of fence info strings, so an example is ordinary markdown
that still highlights on the forge:
```c compiled with -fsyntax-only -Wall -Werror
```c wrap=NAME the same, wrapped in tests/docs_preludes/NAME.pre/.post
```c run=NAME linked against akgl and run headless
```c excerpt=PATH must still appear verbatim in PATH
```c screenshot=NAME also the source of docs/images/NAME.png
```json kind=KIND loaded through the real akgl_*_load_json
```output the exact stdout of the runnable block above it
`run=` is why this links at all: -fsyntax-only proves a call typechecks, not
that the startup order works or that an ATTEMPT block gives back what it took.
`json kind=` exists because the asset formats are documented in prose and read
by four loaders with nothing tying the two together -- util/assets/littleguy.json
is already invalid against the loader it ships with.
A fence with no info string is a hard error, and so is an unknown one. The
failure mode this exists to prevent is passing because it quietly ran nothing,
so an unannotated block is a missing decision rather than a default. Exit status
is the number of failed examples; 2 for a usage error, which is a different
thing and has to be distinguishable.
Proven to fail on all ten of its failure modes -- untagged fence, non-compiling
snippet, stale excerpt, orphan output block, unknown info string, run= output
mismatch, invalid JSON, missing figure, a -Werror warning, and a dangling
preload= -- because a check that has never failed has not been tested.
`-Werror` here although AKGL_WERROR stays off for the library: that option is
off so a new compiler's diagnostic cannot break a consumer's build, and a doc
snippet is not a consumer. A sample that warns is a sample that teaches the
warning.
Registered as `docs_examples` and `docs_screenshots`. No docs-path filter in CI,
deliberately: documentation goes stale because the code moved, not because
somebody edited a chapter.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 20:58:11 -04:00
|
|
|
#include <akgl/util.h>
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief One frame of drawing, supplied by a `c screenshot=NAME` block.
|
|
|
|
|
*
|
|
|
|
|
* tools/docs_screenshot.c brings libakgl up against an offscreen target, calls
|
|
|
|
|
* this, and writes what it drew to `docs/images/NAME.png`. The body is the
|
|
|
|
|
* chapter's own listing, wrapped by tests/docs_preludes/akglframe.pre.
|
|
|
|
|
*/
|
|
|
|
|
akerr_ErrorContext AKERR_NOIGNORE *docs_frame(void);
|
|
|
|
|
|
|
|
|
|
#endif // _AKGL_DOCS_PRELUDE_H_
|