A window, a loop and something drawn in it, in eight lines
A window, a loop, and something drawn in it — in eight lines, with no initialisation, no context object, and no platform code.
One page. Every block here compiles; the ones that open a window are shown without a transcript, because what they produce is a window.
bg.i = rgb(12, 14, 20);
ink.i = rgb(230, 235, 245);
gpu_screen_open(640, 480, "Hello");
gpu_target_fps(60);
while (gpu_frame_begin(bg)) {
gpu_draw_circle(320.0, 240.0, 60.0, ink);
gpu_draw_text(20, 20, "hello", ink);
gpu_frame_end();
}
That is a complete, runnable CX+AI program. Build it and you get a window with a circle in it, at sixty frames a second, that closes when you close it.
gpu_frame_begin(bg) is the loop condition. It clears the frame to the colour you hand it and returns false when the window has been asked to close — so the "is it still open?" test and the "start a frame" call are one thing, and there is no way to write a loop that draws into a window that has gone.
Colours are ints, made by rgb. Not a struct, not three arguments on every call. Name them once at the top and the drawing calls stay short.
red.i = rgb(255, 59, 48);
green.i = rgb(53, 208, 127);
blue.i = rgb(0, 194, 255);
Coordinates are what you would expect. 0, 0 is the top left. Shapes take floats, text takes ints, and both take the colour last.
white.i = rgb(240, 244, 255);
bg.i = rgb(6, 8, 14);
gpu_screen_open(640, 480, "Shapes");
while (gpu_frame_begin(bg)) {
gpu_draw_rect(40.0, 40.0, 120.0, 60.0, white);
gpu_draw_circle(320.0, 240.0, 48.0, white);
gpu_draw_line(40.0, 400.0, 600.0, 400.0, white);
gpu_draw_text(40, 120, "shapes", white);
gpu_frame_end();
}
There is a lot more — rounded rectangles, triangles, textures, sprites, a 3D camera, particles and shaders — and it is all in the Builtins Reference under Graphics. This page is the four calls you need before any of that is interesting.
#define K_LEFT 263
#define K_RIGHT 262
#define K_SPACE 32
bg.i = rgb(6, 8, 14);
ink.i = rgb(230, 235, 245);
x.f = 320.0;
gpu_screen_open(640, 480, "Move me");
while (gpu_frame_begin(bg)) {
if (gpu_key_down(K_LEFT) == 1) { x = x - 6.0; }
if (gpu_key_down(K_RIGHT) == 1) { x = x + 6.0; }
gpu_draw_circle(x, 240.0, 30.0, ink);
gpu_draw_text(20, 20, "arrow keys", ink);
gpu_frame_end();
}
gpu_key_down answers 1 while the key is held. The key numbers are the graphics library's own; the three above are the ones every small program wants, and the rest are in the reference.
Nothing above is desktop code. The identical source compiles to WebAssembly and runs in a page — same window size, same loop, same key codes — which is how the demonstrations on the CX+AI site work. There is no separate web version of a program and no #ifdef to write.
What changes in a tab: the window is a canvas the page owns, and the program cannot reach the machine's filesystem (see Files in, files out). Everything else is the same program.
It is raylib underneath, which is why the call names read the way they do and why the same program looks identical on Windows, Linux and macOS. That is stated rather than hidden: knowing what a layer is makes it easier to search for what a layer can do.
Nothing is drawn until gpu_frame_end(). A frame is begun, drawn into, and ended; a program that forgets the end call shows an empty window rather than a partial one, which is the loud failure rather than the confusing one.