Zen-C

  • Template: cart_zenc - press "Use this template" and you have a working game.
  • Docker image: ghcr.io/notnullgames/null0-cart-zenc:latest (linux/amd64 only - runs emulated on Apple Silicon)
  • Your code: cart/main.zc, compiled with zc (transpiles to C) + wasi-sdk
  • Bindings: carts/zenc/null0.h (baked into the docker image for you)
  • WASI is available, so ordinary file and stdio calls work.

building

You do not install zc (transpiles to C) + wasi-sdk - the docker image has it, and the current null0 bindings, baked in. That is the whole point: there is nothing in your project to keep in sync with the engine.

docker run --rm --user $(id -u):$(id -g) --platform linux/amd64 \
  -v ./cart:/src -v ./webroot:/out \
  ghcr.io/notnullgames/null0-cart-zenc:latest mygame

The template wraps that in npm start, which also serves the result and rebuilds when you save.

Zen-C notes

  • draw_polygon and its siblings take plain i32*/u8*, not structs - the compiler segfaults on a user declaration naming a C-interop struct.

a cart, in Zen-C

This is carts/zenc/simple/main.zc in the engine repo - the same file CI builds into the cart below, so it always compiles.

// null0 Zen-C example: color bars
include "null0.h"

export fn load() {
    // Draw colored bars across the screen, one predefined color constant
    // at a time (zc v0.4.4 segfaults its own compiler on any cart-authored
    // declaration naming Color/Vector/etc - see tools/gen_cart_zenc.js;
    // carts/zenc/demo has a real Vector[] example via the generated
    // primitive-typed draw_polygon wrapper)

    let margin: int = 10;
    let bar_width: int = (SCREEN_WIDTH - margin * 11) / 10;
    let bar_height: int = SCREEN_HEIGHT - margin * 2;

    // draw a couple circles for visual interest
    draw_circle(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 150, WHITE);
    draw_circle(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 100, RED);
    draw_circle(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 50, BLACK);

    // draw each bar individually
    let bx: int = margin;
    draw_rectangle(bx, margin, bar_width, bar_height, RED);
    draw_rectangle_outline(bx, margin, bar_width, bar_height, 1, WHITE);
    bx += bar_width + margin;

    draw_rectangle(bx, margin, bar_width, bar_height, ORANGE);
    draw_rectangle_outline(bx, margin, bar_width, bar_height, 1, WHITE);
    bx += bar_width + margin;

    draw_rectangle(bx, margin, bar_width, bar_height, YELLOW);
    draw_rectangle_outline(bx, margin, bar_width, bar_height, 1, WHITE);
    bx += bar_width + margin;

    draw_rectangle(bx, margin, bar_width, bar_height, GREEN);
    draw_rectangle_outline(bx, margin, bar_width, bar_height, 1, WHITE);
    bx += bar_width + margin;

    draw_rectangle(bx, margin, bar_width, bar_height, BLUE);
    draw_rectangle_outline(bx, margin, bar_width, bar_height, 1, WHITE);
    bx += bar_width + margin;

    draw_rectangle(bx, margin, bar_width, bar_height, PURPLE);
    draw_rectangle_outline(bx, margin, bar_width, bar_height, 1, WHITE);
    bx += bar_width + margin;

    draw_rectangle(bx, margin, bar_width, bar_height, PINK);
    draw_rectangle_outline(bx, margin, bar_width, bar_height, 1, WHITE);
    bx += bar_width + margin;

    draw_rectangle(bx, margin, bar_width, bar_height, SKYBLUE);
    draw_rectangle_outline(bx, margin, bar_width, bar_height, 1, WHITE);
    bx += bar_width + margin;

    draw_rectangle(bx, margin, bar_width, bar_height, LIME);
    draw_rectangle_outline(bx, margin, bar_width, bar_height, 1, WHITE);
    bx += bar_width + margin;

    draw_rectangle(bx, margin, bar_width, bar_height, MAGENTA);
    draw_rectangle_outline(bx, margin, bar_width, bar_height, 1, WHITE);
}

export fn update() {
    // nothing to do per-frame
}

// Other available callbacks:
// export fn unload() { }
// export fn keyDown(key: int) { }
// export fn keyUp(key: int) { }
// export fn buttonDown(button: int, player: uint) { }
// export fn buttonUp(button: int, player: uint) { }
// export fn mouseDown(button: int) { }
// export fn mouseUp(button: int) { }
// export fn mouseMoved(x: float, y: float) { }
carts/zenc/simple/main.zc

callbacks

A cart implements the callbacks it cares about. In Zen-C they look like this:

void update() {}

See anatomy of a cart for the full list and what each one is passed.

more Zen-C carts

the API, in Zen-C

Every null0 function, spelled the way Zen-C spells it. These are read out of the generated bindings themselves, so they match what your editor completes.

colors (7)

Tint a color with another color.

extern Color* color_tint(Color color, Color tint);

Fade a color.

extern Color* color_fade(Color color, f32 alpha);

Change the brightness of a color.

extern Color* color_brightness(Color color, f32 factor);

Invert a color.

extern Color* color_invert(Color color);

Blend 2 colors together.

extern Color* color_alpha_blend(Color dst, Color src);

Change contrast of a color.

extern Color* color_contrast(Color color, f32 contrast);

Interpolate colors.

extern Color* color_bilinear_interpolate(Color color00, Color color01, Color color10, Color color11, f32 coordinateX, f32 coordinateY);
graphics (75)

Create a new blank image.

extern u32 new_image(i32 width, i32 height, Color color);

Copy an image to a new image.

extern u32 image_copy(u32 image);

Create an image from a region of another image.

extern u32 image_subimage(u32 image, i32 x, i32 y, i32 width, i32 height);

Clear the screen.

extern void clear(Color color);

Draw a single pixel on the screen.

extern void draw_point(i32 x, i32 y, Color color);

Draw a line on the screen.

extern void draw_line(i32 startPosX, i32 startPosY, i32 endPosX, i32 endPosY, Color color);

Draw a filled rectangle on the screen.

extern void draw_rectangle(i32 posX, i32 posY, i32 width, i32 height, Color color);

Draw a filled triangle on the screen.

extern void draw_triangle(i32 x1, i32 y1, i32 x2, i32 y2, i32 x3, i32 y3, Color color);

Draw a filled ellipse on the screen.

extern void draw_ellipse(i32 centerX, i32 centerY, i32 radiusX, i32 radiusY, Color color);

Draw a filled circle on the screen.

extern void draw_circle(i32 centerX, i32 centerY, i32 radius, Color color);

Draw a filled polygon on the screen.

extern void draw_polygon(i32* points, i32 numPoints, u8* color);

Draw a filled arc on the screen.

extern void draw_arc(i32 centerX, i32 centerY, f32 radius, f32 startAngle, f32 endAngle, i32 segments, Color color);

Draw a filled round-rectangle on the screen.

extern void draw_rectangle_rounded(i32 x, i32 y, i32 width, i32 height, i32 cornerRadius, Color color);

Draw an image on the screen.

extern void draw_image(u32 src, i32 posX, i32 posY);

Draw a tinted image on the screen.

extern void draw_image_tint(u32 src, i32 posX, i32 posY, Color tint);

Draw an image, rotated, on the screen.

extern void draw_image_rotated(u32 src, i32 posX, i32 posY, f32 degrees, f32 offsetX, f32 offsetY, ImageFilter filter);

Draw an image, flipped, on the screen.

extern void draw_image_flipped(u32 src, i32 posX, i32 posY, bool flipHorizontal, bool flipVertical, bool flipDiagonal);

Draw an image, scaled, on the screen.

extern void draw_image_scaled(u32 src, i32 posX, i32 posY, f32 scaleX, f32 scaleY, f32 offsetX, f32 offsetY, ImageFilter filter);

Draw some text on the screen.

extern void draw_text(u32 font, char* text, i32 posX, i32 posY, Color color);

Save an image to persistant storage.

extern void save_image(u32 image, char* filename);

Load an image from a file in cart.

extern u32 load_image(char* filename);

Resize an image, return copy.

extern u32 image_resize(u32 image, i32 newWidth, i32 newHeight, ImageFilter filter);

Scale an image, return copy.

extern u32 image_scale(u32 image, f32 scaleX, f32 scaleY, ImageFilter filter);

Replace a color in an image, in-place.

extern void image_color_replace(u32 image, Color color, Color replace);

Tint a color in an image, in-place.

extern void image_color_tint(u32 image, Color color);

Fade a color in an image, in-place.

extern void image_color_fade(u32 image, f32 alpha);

Copy a font to a new font.

extern u32 font_copy(u32 font);

Scale a font, return a new font.

extern u32 font_scale(u32 font, f32 scaleX, f32 scaleY, ImageFilter filter);

Load a BMF font from a file in cart.

extern u32 load_font_bmf(char* filename, char* characters);

Load a BMF font from an image.

extern u32 load_font_bmf_from_image(u32 image, char* characters);

Measure the size of some text.

extern Dimensions* measure_text(u32 font, char* text, i32 textLength);

Meaure an image (use 0 for screen).

extern Dimensions* measure_image(u32 image);

Load a TTY font from a file in cart.

extern u32 load_font_tty(char* filename, i32 glyphWidth, i32 glyphHeight, char* characters);

Load a TTY font from an image.

extern u32 load_font_tty_from_image(u32 image, i32 glyphWidth, i32 glyphHeight, char* characters);

Load a TTF font from a file in cart.

extern u32 load_font_ttf(char* filename, i32 fontSize);

Invert the colors in an image, in-place.

extern void image_color_invert(u32 image);

Calculate a rectangle representing the available alpha border in an image.

extern Rectangle* image_alpha_border(u32 image, f32 threshold);

Crop an image, in-place.

extern void image_crop(u32 image, i32 x, i32 y, i32 width, i32 height);

Crop an image based on the alpha border, in-place.

extern void image_alpha_crop(u32 image, f32 threshold);

Adjust the brightness of an image, in-place.

extern void image_color_brightness(u32 image, f32 factor);

Flip an image, in-place.

extern void image_flip(u32 image, bool horizontal, bool vertical);

Change the contrast of an image, in-place.

extern void image_color_contrast(u32 image, f32 contrast);

Use an image as an alpha-mask on another image.

extern void image_alpha_mask(u32 image, u32 alphaMask, i32 posX, i32 posY);

Create a new image, rotating another image.

extern u32 image_rotate(u32 image, f32 degrees, ImageFilter filter);

Create a new image of a gradient.

extern u32 image_gradient(i32 width, i32 height, Color topLeft, Color topRight, Color bottomLeft, Color bottomRight);

Unload an image.

extern void unload_image(u32 image);

Unload a font.

extern void unload_font(u32 font);

Clear an image.

extern void clear_image(u32 destination, Color color);

Draw a single pixel on an image.

extern void draw_point_on_image(u32 destination, i32 x, i32 y, Color color);

Draw a line on an image.

extern void draw_line_on_image(u32 destination, i32 startPosX, i32 startPosY, i32 endPosX, i32 endPosY, Color color);

Draw a filled rectangle on an image.

extern void draw_rectangle_on_image(u32 destination, i32 posX, i32 posY, i32 width, i32 height, Color color);

Draw a filled triangle on an image.

extern void draw_triangle_on_image(u32 destination, i32 x1, i32 y1, i32 x2, i32 y2, i32 x3, i32 y3, Color color);

Draw a filled ellipse on an image.

extern void draw_ellipse_on_image(u32 destination, i32 centerX, i32 centerY, i32 radiusX, i32 radiusY, Color color);

Draw a circle on an image.

extern void draw_circle_on_image(u32 destination, i32 centerX, i32 centerY, i32 radius, Color color);

Draw a filled polygon on an image.

extern void draw_polygon_on_image(u32 destination, i32* points, i32 numPoints, u8* color);

Draw a filled round-rectangle on an image.

extern void draw_rectangle_rounded_on_image(u32 destination, i32 x, i32 y, i32 width, i32 height, i32 cornerRadius, Color color);

Draw an image on an image.

extern void draw_image_on_image(u32 destination, u32 src, i32 posX, i32 posY);

Draw a tinted image on an image.

extern void draw_image_tint_on_image(u32 destination, u32 src, i32 posX, i32 posY, Color tint);

Draw an image, rotated, on an image.

extern void draw_image_rotated_on_image(u32 destination, u32 src, i32 posX, i32 posY, f32 degrees, f32 offsetX, f32 offsetY, ImageFilter filter);

Draw an image, flipped, on an image.

extern void draw_image_flipped_on_image(u32 destination, u32 src, i32 posX, i32 posY, bool flipHorizontal, bool flipVertical, bool flipDiagonal);

Draw an image, scaled, on an image.

extern void draw_image_scaled_on_image(u32 destination, u32 src, i32 posX, i32 posY, f32 scaleX, f32 scaleY, f32 offsetX, f32 offsetY, ImageFilter filter);

Draw some text on an image.

extern void draw_text_on_image(u32 destination, u32 font, char* text, i32 posX, i32 posY, Color color);

Draw a outlined (with thickness) rectangle on the screen.

extern void draw_rectangle_outline(i32 posX, i32 posY, i32 width, i32 height, i32 thickness, Color color);

Draw a outlined (with thickness) triangle on the screen.

extern void draw_triangle_outline(i32 x1, i32 y1, i32 x2, i32 y2, i32 x3, i32 y3, i32 thickness, Color color);

Draw a outlined (with thickness) ellipse on the screen.

extern void draw_ellipse_outline(i32 centerX, i32 centerY, i32 radiusX, i32 radiusY, i32 thickness, Color color);

Draw a outlined (with thickness) circle on the screen.

extern void draw_circle_outline(i32 centerX, i32 centerY, i32 radius, i32 thickness, Color color);

Draw a outlined (with thickness) polygon on the screen.

extern void draw_polygon_outline(i32* points, i32 numPoints, i32 thickness, u8* color);

Draw a outlined (with thickness) arc on the screen.

extern void draw_arc_outline(i32 centerX, i32 centerY, f32 radius, f32 startAngle, f32 endAngle, i32 segments, i32 thickness, Color color);

Draw a outlined (with thickness) round-rectangle on the screen.

extern void draw_rectangle_rounded_outline(i32 x, i32 y, i32 width, i32 height, i32 cornerRadius, i32 thickness, Color color);

Draw a outlined (with thickness) rectangle on an image.

extern void draw_rectangle_outline_on_image(u32 destination, i32 posX, i32 posY, i32 width, i32 height, i32 thickness, Color color);

Draw a outlined (with thickness) triangle on an image.

extern void draw_triangle_outline_on_image(u32 destination, i32 x1, i32 y1, i32 x2, i32 y2, i32 x3, i32 y3, i32 thickness, Color color);

Draw a outlined (with thickness) ellipse on an image.

extern void draw_ellipse_outline_on_image(u32 destination, i32 centerX, i32 centerY, i32 radiusX, i32 radiusY, i32 thickness, Color color);

Draw a outlined (with thickness) circle on an image.

extern void draw_circle_outline_on_image(u32 destination, i32 centerX, i32 centerY, i32 radius, i32 thickness, Color color);

Draw a outlined (with thickness) polygon on an image.

extern void draw_polygon_outline_on_image(u32 destination, i32* points, i32 numPoints, i32 thickness, u8* color);

Draw a outlined (with thickness) round-rectangle on an image.

extern void draw_rectangle_rounded_outline_on_image(u32 destination, i32 x, i32 y, i32 width, i32 height, i32 cornerRadius, i32 thickness, Color color);
gui (10)

Begin a GUI window. Returns false if the window is collapsed or closed - skip its contents, but still call gui_end_window.

extern bool gui_begin_window(char* title, Rectangle rect);

End the current GUI window.

extern void gui_end_window();

A button. Returns true when it is clicked.

extern bool gui_button(char* label);

A static text label.

extern void gui_label(char* text);

A block of wrapping text.

extern void gui_text(char* text);

A checkbox. Returns the (possibly changed) state.

extern bool gui_checkbox(char* label, bool state);

A slider. Returns the (possibly changed) value.

extern f32 gui_slider(f32 value, f32 low, f32 high);

Set the current layout row - the column widths (negative for flexible), and the row height.

extern void gui_layout_row(i32* widths, i32 numWidths, i32 height);

Finish building the GUI for this frame. Called automatically at the end of update if you do not call it.

extern void gui_end();

Draw the GUI to an image (0 is the screen).

extern void gui_draw(u32 dst);
input (12)

Has the key been pressed? (tracks unpress/read correctly.)

extern bool key_pressed(Key key);

Is the key currently down?

extern bool key_down(Key key);

Has the key been released? (tracks press/read correctly.)

extern bool key_released(Key key);

Is the key currently up?

extern bool key_up(Key key);

Has the button been pressed? (tracks unpress/read correctly.)

extern bool gamepad_button_pressed(i32 gamepad, GamepadButton button);

Is the button currently down?

extern bool gamepad_button_down(i32 gamepad, GamepadButton button);

Has the button been released? (tracks press/read correctly.)

extern bool gamepad_button_released(i32 gamepad, GamepadButton button);

Get current position of mouse.

extern Vector* mouse_position();

Has the button been pressed? (tracks unpress/read correctly.)

extern bool mouse_button_pressed(MouseButton button);

Is the button currently down?

extern bool mouse_button_down(MouseButton button);

Has the button been released? (tracks press/read correctly.)

extern bool mouse_button_released(MouseButton button);

Is the button currently up?

extern bool mouse_button_up(MouseButton button);
sound (7)

Load a sound from a file in cart.

extern u32 load_sound(char* filename);

Play a sound.

extern void play_sound(u32 sound, bool loop);

Stop a sound.

extern void stop_sound(u32 sound);

Unload a sound.

extern void unload_sound(u32 sound);

Speak some text and return a sound. Set things to 0 for defaults.

extern u32 tts_sound(char* text, bool phonetic, i32 pitch, i32 speed, i32 throat, i32 mouth, bool sing);

Create Sfx sound.

extern u32 sfx_sound(SfxParams params);

Create Sfx parameters.

extern SfxParams* sfx_generate(SfxPresetType type);
tile (38)

Load a tilemap (a Tiled map, exported as JSON) from a file in cart.

extern u32 load_tilemap(char* filename);

Unload a tilemap.

extern void unload_tilemap(u32 tilemap);

Update a tilemap's animation timers (deltaTime is in seconds).

extern void tile_update(u32 tilemap, f32 deltaTime);

Get the size of a tilemap, in tiles.

extern Dimensions* tile_map_size(u32 tilemap);

Get the size of a single tile of a tilemap, in pixels.

extern Dimensions* tile_tile_size(u32 tilemap);

Get a custom property of a tilemap, by name (PROP_NONE when there is no such property.)

extern TilemapProp* tile_map_prop(u32 tilemap, char* name);

Get the number of custom properties on a tilemap.

extern i32 tile_map_prop_count(u32 tilemap);

Get a custom property of a tilemap, by index (PROP_NONE when out of range.)

extern TilemapProp* tile_map_prop_at(u32 tilemap, i32 index);

Draw a tilemap on the screen.

extern void tile_draw(u32 tilemap, i32 posX, i32 posY);

Draw a tilemap on the screen, tinted by a color.

extern void tile_draw_tint(u32 tilemap, i32 posX, i32 posY, Color tint);

Draw a tilemap on an image.

extern void tile_draw_on_image(u32 dst, u32 tilemap, i32 posX, i32 posY);

Render a whole tilemap to a new image.

extern u32 tilemap_image(u32 tilemap);

Get the number of layers in a tilemap. Layers are numbered depth-first, so the children of a group layer have their own indexes too.

extern i32 tile_layer_count(u32 tilemap);

Get the index of a layer of a tilemap, by name (-1 when there is no such layer.)

extern i32 tile_layer_index(u32 tilemap, char* name);

Get the name of a layer of a tilemap.

extern char* tile_layer_name(u32 tilemap, i32 layer);

Get the kind of a layer of a tilemap.

extern TileLayerKind tile_layer_type(u32 tilemap, i32 layer);

Get the size of a layer of a tilemap, in tiles.

extern Dimensions* tile_layer_size(u32 tilemap, i32 layer);

Get whether a layer of a tilemap is visible. Drawing a layer that Tiled marked hidden draws nothing.

extern bool tile_layer_visible(u32 tilemap, i32 layer);

Get a custom property of a layer of a tilemap, by name (PROP_NONE when there is no such property.)

extern TilemapProp* tile_layer_prop(u32 tilemap, i32 layer, char* name);

Get the number of custom properties on a layer of a tilemap.

extern i32 tile_layer_prop_count(u32 tilemap, i32 layer);

Get a custom property of a layer of a tilemap, by index (PROP_NONE when out of range.)

extern TilemapProp* tile_layer_prop_at(u32 tilemap, i32 layer, i32 index);

Draw a single layer of a tilemap on the screen.

extern void tile_draw_layer(u32 tilemap, i32 layer, i32 posX, i32 posY);

Draw a single layer of a tilemap on the screen, tinted by a color.

extern void tile_draw_layer_tint(u32 tilemap, i32 layer, i32 posX, i32 posY, Color tint);

Draw a single layer of a tilemap on an image.

extern void tile_draw_layer_on_image(u32 dst, u32 tilemap, i32 layer, i32 posX, i32 posY);

Render a single layer of a tilemap to a new image.

extern u32 tile_layer_image(u32 tilemap, i32 layer);

Get the gid of the tile at a column/row in a tilemap layer.

extern i32 tile_get_tile(u32 tilemap, i32 layer, i32 column, i32 row);

Set the gid of the tile at a column/row in a tilemap layer. Swapping a gid is how a cart keeps changing state in the map itself.

extern void tile_set_tile(u32 tilemap, i32 layer, i32 column, i32 row, i32 gid);

Draw a single tile from a tilemap on the screen.

extern void tile_draw_tile(u32 tilemap, i32 gid, i32 posX, i32 posY);

Get a copy of the image of a single tile in a tilemap.

extern u32 tile_image(u32 tilemap, i32 gid);

Get a custom property of a tile of a tilemap, by name (PROP_NONE when there is no such property.) These come from the tileset, so every tile with this gid shares them.

extern TilemapProp* tile_gid_prop(u32 tilemap, i32 gid, char* name);

Get the number of custom properties on a tile of a tilemap.

extern i32 tile_gid_prop_count(u32 tilemap, i32 gid);

Get a custom property of a tile of a tilemap, by index (PROP_NONE when out of range.)

extern TilemapProp* tile_gid_prop_at(u32 tilemap, i32 gid, i32 index);

Get the number of objects on an object-layer of a tilemap.

extern i32 tile_object_count(u32 tilemap, i32 layer);

Get an object from an object-layer of a tilemap.

extern TilemapObject* tile_object(u32 tilemap, i32 layer, i32 index);

Get the index of an object on an object-layer of a tilemap, by name (-1 when there is no such object.)

extern i32 tile_object_index(u32 tilemap, i32 layer, char* name);

Get a custom property of an object of a tilemap, by name (PROP_NONE when there is no such property.)

extern TilemapProp* tile_object_prop(u32 tilemap, i32 layer, i32 index, char* name);

Get the number of custom properties on an object of a tilemap.

extern i32 tile_object_prop_count(u32 tilemap, i32 layer, i32 index);

Get a custom property of an object of a tilemap, by index (PROP_NONE when out of range.)

extern TilemapProp* tile_object_prop_at(u32 tilemap, i32 layer, i32 index, i32 propIndex);
utilities (5)

Get system-time (ms) since unix epoch.

extern u64 current_time();

Get the change in time (seconds) since the last update run.

extern f32 delta_time();

Get a random integer between 2 numbers.

extern i32 random_int(i32 min, i32 max);

Get the random-seed.

extern u64 random_seed_get();

Set the random-seed.

extern void random_seed_set(u64 seed);