Files
libakgl/docs/images/README.md
Andrew Kesterson 8ac291d2dd 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

2.4 KiB

The figures in this directory are generated, and are tracked deliberately

Every .png beside this file is output, not art. Each one is rendered by tools/docs_screenshots.sh from a ```c screenshot=NAME block in a chapter — the same code the reader is looking at, compiled against tools/docs_screenshot.c, run headless, and read back off the render target.

They are committed to the repository on purpose: a reader looking at the manual on the forge has no build tree, and a chapter whose figures only exist after cmake --build renders as a page of broken images. This is the same tracked-generated-artifact contract AGENTS.md spells out for include/akgl/SDL_GameControllerDB.h. Do not delete them, do not add them to .gitignore, and do not "clean up" the fact that generated files are tracked.

Working rules:

  • Never hand-edit one, and never replace one with a hand-taken screenshot. The whole point of the arrangement is that the picture follows the code. A figure that was retouched is a figure that has stopped being of the listing beside it, silently — which is exactly the failure this replaced.
  • An ordinary build does not touch them. Regeneration is cmake --build build --target docs_screenshots, and nothing else runs the script. A build that quietly rewrote eight binaries would put that diff in front of whoever happened to run make.
  • Regenerate as a deliberate change, in the same commit as whatever moved the picture, so the binary diff is attributable.
  • ctest -R docs_screenshots re-renders every figure and compares it byte for byte, into a scratch directory. It never repairs what it finds: a test that fixes what it is measuring passes the second time for the wrong reason.
  • ctest -R docs_examples fails a tagged block with no image here, so a new figure cannot be added to a chapter and then forgotten.

A byte comparison of a rendered PNG is a deliberate bet: that the dummy video driver and the software renderer are reproducible run to run and build to build. They are. What that does not cover is an SDL upgrade shifting one pixel of a diagonal — and the answer to that is to regenerate the figures in the same commit as the bump, not to weaken the check to a size comparison that would pass for every wrong picture of the right dimensions.

See docs/MAINTENANCE.md for the fence tags and the rest of the harness.