A small, dependency-free utility layer on top of MinilibX (bundled as a git submodule) for building graphical C programs — raycasters, fractal explorers, game-of-life simulations, image editors, or anything else that needs a window and a pixel buffer. It grew out of the 42 School curriculum (fdf, so_long, cub3d, fract-ol, ...) but there's nothing 42-specific about it: any project built on MinilibX can use it.
MinilibX gives you a window, an image buffer, and not much else. my_mlx fills in the gaps that every graphical project ends up rewriting by hand: safe pixel access, image compositing with transparency, color parsing/blending, resizing, and clean teardown — all as small, single-purpose, -Wall -Wextra -Werror-clean functions compiled into a static library (libmymlx.a).
If you'd rather understand how an MLX image actually works under the hood than just call the functions below, I wrote about it here: At Least I Know How to Manipulate an MLX Image 🤷🏿♂️.
- Repository layout
- Clone
- Build
- Using it in another project
- Data types (
inc/structs.h) - API reference
- Example
.
├── inc/ # public headers (my_mlx.h, structs.h)
├── src/ # library implementation (one function per file)
├── minilibx-linux/ # MinilibX, as a git submodule
└── Makefile # builds minilibx-linux, then libmymlx.a
This repository uses a git submodule for minilibx-linux.
git clone --recurse-submodules <repo-url>If you already cloned the repository, initialize the submodule with:
git submodule update --init --recursivemakeThis first builds minilibx-linux/libmlx.a, then compiles everything under src/ into libmymlx.a.
Add this repository as a submodule of your project (e.g. under libs/my_mlx), then in your project's Makefile:
MY_MLX = libs/my_mlx
MLX = $(MY_MLX)/minilibx-linux
CFLAGS += -I $(MY_MLX)/inc -I $(MLX)
LDFLAGS += -L $(MY_MLX) -lmymlx -L $(MLX) -lmlx -lXext -lX11 -lm -lbsd
$(NAME): $(MY_MLX)/libmymlx.a
$(CC) $(OBJ) $(LDFLAGS) -o $(NAME)
$(MY_MLX)/libmymlx.a:
@$(MAKE) -C $(MY_MLX)Then in your source:
#include "my_mlx.h"| Type | Purpose |
|---|---|
t_int_point / t_dbl_point |
2D int/double coordinate pair (x, y) |
t_argb |
Unpacked color channels (a, r, g, b) |
t_color |
A { name, value } entry used by the named-color table |
t_img |
An image: MLX handle, pixel buffer address, line_len, bpp, endian, size |
t_img_to_img |
Parameters for a blit: dst/src/aux images, dst_point/src_point, size, and filter/skip/color_aux transparency options |
| Function | Description |
|---|---|
my_mlx_init_img(img) |
Zeroes out a t_img (used internally after creation/destruction, safe to call directly to prepare a fresh struct). |
my_mlx_new_img(mlx, img, size) |
Allocates a new MLX image of size and caches its pixel buffer address. Fails cleanly (false) on invalid size or allocation failure. |
my_mlx_xpm_file_to_img(mlx, img, path) |
Loads a .xpm file into a new image and caches its pixel buffer address, sizing img to the file's dimensions. |
my_mlx_get_data_addr(img) |
Fetches (or refreshes) the raw pixel buffer address, bpp, line_len, and endian for an already-created image. |
my_mlx_duplicate_img(mlx, dst, src) |
Allocates dst as an independent, pixel-for-pixel copy of src. |
my_mlx_resize_img(mlx, img, size) |
Resizes img in place to size using nearest-neighbor sampling, replacing the underlying MLX image. |
| Function | Description |
|---|---|
my_mlx_pixel_put(img, crd, color) |
Bounds-checked pixel write. Returns false instead of writing out of bounds. |
my_mlx_get_pixel(img, crd) |
Bounds-checked pixel read. Returns BLACK for out-of-bounds coordinates. |
my_mlx_color_img(img, color) |
Fills an entire image with a solid color. |
my_mlx_draw_line_to_img(img, crd, size, color) |
Fills a size-sized rectangular region starting at crd with a solid color, clipped to the image bounds. |
| Function | Description |
|---|---|
my_mlx_put_img_to_img(base) |
Copies a region (base->size) from base->src at base->src_point onto base->dst at base->dst_point, auto-clipped to both images' bounds. When base->filter is set, pixels equal to TRANSPARENT are handled specially: skipped entirely (base->skip), replaced with base->color_aux, or sampled from base->aux at the same coordinates — enabling sprite masking, backgrounds, and layered draws. |
| Function | Description |
|---|---|
my_mlx_get_color(a, r, g, b) |
Packs four 8-bit channels into a single ARGB int. |
my_mlx_get_argb(color) |
Unpacks an ARGB int back into a t_argb. |
my_mlx_get_lerp_color(start, end, interpolant) |
Linearly interpolates between two colors (interpolant in [0, 1]) — useful for gradients, fades, and heatmaps. |
my_mlx_get_color_from_name(name) |
Case-insensitive lookup of a color by its X11 name (e.g. "steel blue", "steelblue3"); returns -1 if not found. |
my_mlx_get_available_color(void) |
Stateful iterator over the ~750 named colors — call repeatedly to enumerate every name, NULL-terminated, then automatically resets for the next enumeration. |
| Function | Description |
|---|---|
my_mlx_destroy_img(mlx, img) |
Destroys the underlying MLX image and resets the t_img struct. |
my_mlx_destroy_window(mlx, win) |
Destroys the MLX window and nulls the pointer. |
my_mlx_destroy_init(mlx) |
Destroys the MLX display connection, frees, and nulls the pointer. |
- Colors:
BLACK,WHITE,RED,GREEN,BLUE,TRANSPARENT— packed ARGBints.TRANSPARENTis the sentinel valuemy_mlx_put_img_to_imglooks for whenfilteris enabled. - Keys:
ESC_KEY,F1_KEY–F12_KEY, arrow keys,SHIFT_LEFT_KEY/CTRL_LEFT_KEY/ALT_KEY/etc., numpad keys (NUM_LOCK_*), and more — readable names for the raw X11 keysyms returned bymlx_key_hook.
#include "my_mlx.h"
void *mlx;
void *win;
t_img sprite;
t_img canvas;
mlx = mlx_init();
win = mlx_new_window(mlx, 800, 600, "demo");
my_mlx_xpm_file_to_img(mlx, &sprite, "assets/player.xpm");
my_mlx_new_img(mlx, &canvas, (t_int_point){800, 600});
my_mlx_color_img(&canvas, my_mlx_get_color_from_name("midnight blue"));
my_mlx_put_img_to_img(&(t_img_to_img){
.dst = &canvas,
.src = &sprite,
.dst_point = (t_int_point){100, 100},
.src_point = (t_int_point){0, 0},
.size = sprite.size,
.filter = true,
.skip = true, /* leave the canvas showing through transparent pixels */
});
mlx_put_image_to_window(mlx, win, canvas.img, 0, 0);