raylib API coverage
What raylib surface area is proven working against this port, and how. Each section cites the committed example that proves it — these examples double as the running test suite for the claims below.
Fonts load like textures (from the text arc, 2026-07-03)
Custom font loading works with zero wrapper changes. LoadFont (BMFont .fnt + its .png atlas) and LoadFontEx (a TTF rasterized at load, with a base size + glyph count) both return a Font native struct — treat it exactly like a Texture2D: bind it in the outer let, draw with DrawTextEx inside the loop, UnloadFont after. LoadFontEx's codepoint-array arg is passed as cpp/nullptr for the default set. .-baseSize reads back fine (nth-box it for the cpp/float size arg). Proof lines: FONT: ... Font loaded successfully, FONT: Data loaded successfully (32 pixel size | 184 glyphs) (font_loading.jank). String literals MAY be UTF-8 (disproving an earlier version of this note): codepoints_loading.jank defs the Japanese Iroha pangram in-source, and the lexer, LoadCodepoints, and DrawTextEx all handle it. The ASCII-only restriction is about COMMENTS (the em-dash lex/invalid-unicode trip).
Models load like fonts (from the model arc, 2026-07-11)
Mesh/Model loading works with zero wrapper changes — the long-assumed "LoadModel blocker" was never real, exactly as with Font. Proven in texture_tiling.jank:
(cpp/GenMeshCube (cpp/float 1.0) ...)returns aMeshby value; passing it inline tocpp/LoadModelFromMeshyields aModelthat binds as an outer-let local (pointers inside and all) and draws withcpp/DrawModelinside the loop. Proof line:VAO: [ID 2] Mesh uploaded successfully to VRAM (GPU).- Material field writes need a pointer shim. The C idiom
model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = tex(and.shader = s) has no jank spelling; a two-line C shim taking(Model* m, Texture2D tex)does the assignment, called with(cpp/& model)— the same address-of pattern asImage*/UpdateCamera(cpp-interop-toolbox.md). UnloadModelafter the loop, as usual for create-once resources.LoadModelfrom a FILE works too (model_loading.jank, the castle OBJ + its .png diffuse): same shape, just returns aModel. Readingmodel.meshes[0]forGetMeshBoundingBoxstays a one-line shim through(cpp/& model)(a struct-arraycpp/agetwould probably also work per the GlyphInfo probe, but the shim is certain).- GLB works too (
cel_shading.jank, the old_car_new.glb toon car):MODEL: ... Model basic data (glb) loaded successfully. Reading a Shader back off the material (m->materials[0].shader) is a Shader-returning shim bound to a let-local, like any create-once native. - Animations, deep Mesh edits and bare Materials work too (2026-07-11):
LoadModelAnimations'ModelAnimation*+int*out-param stay behind C statics with index-based wrappers, andUpdateModelAnimationruns per frame (shadowmap_rendering.jank); atexcoords2channel can be RL_MALLOC'd, filled and wired to a vertex attribute through(cpp/& mesh)(lightmap_rendering.jank);LoadMaterialDefaultbinds by value with(cpp/& material)field-write shims (mesh_instancing.jank, which also provesDrawMeshInstancedover a C-static Matrix array). - Every model format is proven (2026-07-11): OBJ (
model_loading), GLB (cel_shading), IQM incl. separate animation files (loading_iqm), M3D incl. skeleton access (loading_m3d), and VOX (loading_vox, which also provesUpdateCameraProwith inline movement/rotation Vector3s andGetModelBoundingBox).
Compute shaders work (GL 4.3 wrapper build, 2026-07-11)
rlgl_compute.jank proves the whole compute pipeline: compile (rlLoadShader src RL_COMPUTE_SHADER + rlLoadShaderProgramCompute, kept in a path-taking C shim), SSBOs (rlLoadShaderBuffer with cpp/nullptr data), rlBindShaderBuffer, and rlComputeShaderDispatch — all direct rlgl calls with jank-int ids. Prerequisites and patterns:
- jank-raylib-sys must be built with
OPENGL_VERSION "4.3"(set in its jank-build.bb since 2026-07-11): under the default 3.3 the rlgl compute functions compile to no-ops. 4.3 is the same GL 3.3 feature set plus compute, so the GLSL-330 examples are unaffected (regression checked). Proof line:GL: Compute shaders supported.
OPENGL_VERSION "3.3" (macOS's native GL backend caps at 4.1, so a global 4.3 build broke window creation for every example on macOS). rlgl-compute now needs the manual 4.3 override described above, which will not work on macOS regardless of the override — see the root README's "Known limitations" section.- SSBO ids are plain unsigned ints — hold them as jank ints and the classic ping-pong buffer swap (
ssboA <-> ssboB) is justrecurwith the loop vars exchanged. No native value crosses the loop. - A CPU-side staging struct uploaded with
rlUpdateShaderBuffer(&struct+ sizeof) stays acpp/rawstatic behind buffer/count/flush wrappers, like any frame-crossing native state.
rlgl and textures (from the shapes-completing arc)
- rlgl immediate mode works directly —
(:include "raylib.h" "rlgl.h")givesrlBegin/rlColor4ub/rlColor4f/rlVertex2f/rlEnd(rlgl_triangle.jank), custom blend pipelines viarlSetBlendFactors+rlSetBlendMode cpp/BLEND_CUSTOM+rlDrawRenderBatchActive(top_down_lights.jank), and full vertex-colored batches (rectangle_advanced.jank). Raw GL constants pass as plain ints. - The rlgl matrix stack works in 3D:
rlPushMatrix/rlPopMatrix/rlRotatef/rlTranslatef/rlScalefnest hierarchical transforms insideBeginMode3D, and regular raylib draws (DrawSphere) render through the same batch so the stack applies to them (rlgl_solar_system.jank- Sun/Earth/Moon). - Color field read-back works: bind a returned Color to a let-local and read
(.-r c)/(.-g c)/(.-b c)/(.-a c)— feed them native-to-native intorlColor4ub, or box with(int (+ 0.0 ...))to store as jank ints (rlgl_color_wheel.jank). - Image → Texture loading works:
(cpp/GenImageChecked ...)→(cpp/LoadTextureFromImage img)→(cpp/UnloadImage img), with the Texture2D held in the outerletlike a RenderTexture (top_down_lights.jank). All nineGenImage*algorithms work (image_generation.jank). LoadTexturefrom a PNG file works — a jank string coerces to theconst char*path. Resource files come from the vendored raylib submodule via a path relative to theraylib-examples/working dir:../jank-raylib-sys/raylib/examples/textures/resources/...(logo_texture.jank; the run log'sFILEIO: ... File loaded successfullyis the proof to grep for).- N textures = N outer-let bindings + a nested-if dispatch on the current index — the array-of-textures idiom has no direct jank shape (
image_generation.jank's nine). - Per-entity RenderTexture caches don't map to jank — native handles can't live in a jank vector. Restructure to one reused scratch RT plus a rebuild-on-dirty pass (
top_down_lights.jankreplaces the C's 16 cached per-light masks this way). - Variable-winding fans: when a quad's winding depends on runtime geometry (shadow volumes), draw each triangle in BOTH windings or backface culling eats half of them (
top_down_lights.jank's draw-quad).
Audio (from the textures arc, 2026-07-03)
raylib audio works with zero wrapper changes. InitAudioDevice, LoadSound, PlaySound, UnloadSound and CloseAudioDevice are plain raylib.h functions compiled into libraylib (miniaudio / Core Audio backend on macOS). The Sound value is a native struct — same rules as Texture2D: bind it in the outer let, use it inside the frame loop via lexical capture, unload after (sprite_button.jank). The run log's AUDIO: Device initialized successfully + WAVE: Data loaded successfully are the proof lines to grep for. OGG decoding works too (sound_loading.jank), and so do music streams: LoadMusicStream (MP3), UpdateMusicStream once per frame, Play/Stop/Pause/Resume, SetMusicPan/SetMusicVolume (jank real through cpp/float), and GetMusicTimePlayed/GetMusicTimeLength boxed at the binding site (music_stream.jank; proof line STREAM: Initialized successfully). The remaining audio surface to probe is the callback-taking APIs (SetAudioStreamCallback, audio processors) — likely a real blocker, same class as C function pointers elsewhere.
3D mode (from the sound-positioning port, 2026-07-03)
Basic 3D works. cpp/Camera3D constructs inline from three nested cpp/Vector3 args + fovy + cpp/CAMERA_PERSPECTIVE, binds as an outer-let local, and drives BeginMode3D/EndMode3D; DrawGrid and DrawSphere (Vector3 built inline as a call arg) render inside it (sound_positioning.jank). Two constraints shape 3D ports:
- Free-look cameras WORK now (2026-07-05):
UpdateCamera ((cpp/& camera) mode)forms the pointer with the image-processing address-of pattern (cpp-interop-toolbox.md) on an OUTER-let Camera3D, and the mutation persists across frames (probe: 100 orbital frames drifted position.x from 10.0 to 14.03) —camera_3d_free.jank. Struct FIELD writes still have no jank syntax; a one-line pointer shim does them (jank_cam_retarget). The older per-frame-rebuild workaround remains valid and simpler when the camera path is fully jank-driven:billboard_rendering.jankconstructs the wholecpp/Camera3Das a frame-let local from an accumulated angle, andDrawBillboard*accept it by value.BoundingBoxalso constructs inline from two nestedcpp/Vector3s forCheckCollisionBoxes/CheckCollisionBoxSphere(box_collisions.jank). - No raymath vector helpers through jank fns:
Vector3Subtractetc. return native structs, fine inline, but a chain of them can't thread jank helper fns — do the vector math as scalar jank arithmetic on plain reals instead (the attenuation/pan math insound_positioning.jankreplaces five raymath calls this way).