Skip to content

C API

The engine's stable ABI is a small C header, engine/capi/include/sky_api.h. The SwiftUI editor is built on it, and any language with a C FFI (Swift, Python, Rust, C#, Zig, JavaScript) can embed the engine with it.

Design

Skywalker C API — the stable ABI boundary of the engine.

Why a C API? It is the one interface every language can call without a custom toolchain: Swift (the macOS editor), Python, Rust, C#, Zig, JavaScript (via FFI)... It is intentionally narrow: most functionality is reached through sky_call_tool, the exact same tool surface that agents use over MCP. Only latency-critical paths (rendering, camera, picking, dragging, input) get dedicated functions.

Ownership: strings returned as char* are heap-allocated and MUST be released with sky_string_free(). Input strings are borrowed for the duration of the call. Threading: all functions must be called from the thread that created the engine, except where noted.

Lifetime

Declaration Notes
SkyEngine* sky_engine_create(const char* project_dir);
void sky_engine_destroy(SkyEngine* engine);
const char* sky_version(void); /* static string, do not free */ void sky_string_free(char* str);

Tools (same surface as MCP)

Declaration Notes
char* sky_call_tool(SkyEngine* engine, const char* name, const char* args_json, const char* actor); Returns an MCP CallToolResult JSON: {"content":[...],"isError":bool,"structuredContent":{...}}
typedef struct SkyPendingCall SkyPendingCall; Non-blocking variant for tools that run slow external programs (design apps). Runs the quick part * on the calling (engine) thread. Returns the final result JSON, or NULL when the tool deferred slow * work: then *pending is set. Call sky_pending_run(pending) on ANY thread (it may take seconds), and * afterwards sky_pending_finish on the engine thread, which returns the result JSON and frees it.
char* sky_call_tool_begin(SkyEngine* engine, const char* name, const char* args_json, const char* actor, SkyPendingCall** pending);
void sky_pending_run(SkyPendingCall* pending);
char* sky_pending_finish(SkyEngine* engine, SkyPendingCall* pending);
char* sky_tools_list(SkyEngine* engine); Returns the MCP tools/list payload: {"tools":[{name,title,description,inputSchema,annotations}]}

Frame loop

Declaration Notes
void sky_update(SkyEngine* engine, double seconds); Pumps cross-thread jobs (agent requests) and advances the simulation when playing.
int sky_render_to_layer(SkyEngine* engine, void* metal_layer, int width, int height); Renders the editor view into a CAMetalLayer (passed as void*). Returns 0 on success.
uint64_t sky_scene_revision(SkyEngine* engine); Monotonic counter; changes whenever scene data changes (use to refresh UI lazily).
char* sky_poll_events(SkyEngine* engine); JSON array of activity events since the last call (edits, tool calls, logs, play state).
const char* sky_play_state(SkyEngine* engine); "editing" | "playing" | "paused" (static string)

Editor camera & interaction

Declaration Notes
void sky_camera_orbit(SkyEngine* engine, float dyaw_degrees, float dpitch_degrees);
void sky_camera_pan(SkyEngine* engine, float dx, float dy); /* fractions of viewport height */ void sky_camera_zoom(SkyEngine* engine, float factor); /* <1 zooms in */ uint64_t sky_pick(SkyEngine* engine, float x, float y, int width, int height); /* 0 = nothing */ void sky_set_selection(SkyEngine* engine, const uint64_t* ids, int count, const char* actor);
int sky_get_selection(SkyEngine* engine, uint64_t* out_ids, int capacity); /* returns count */ void sky_drag_begin(SkyEngine* engine, uint64_t entity, float x, float y, int width, int height);
void sky_drag_update(SkyEngine* engine, float x, float y, int width, int height);
void sky_drag_end(SkyEngine* engine);

Transform gizmo: mode 0 = none, 1 = move, 2 = rotate, 3 = scale

Declaration Notes
void sky_gizmo_set_mode(SkyEngine* engine, int mode, int local_space);
int sky_gizmo_mode(SkyEngine* engine);
void sky_gizmo_set_snap(SkyEngine* engine, float translate_step, float rotate_step_degrees);
int sky_gizmo_hover(SkyEngine* engine, float x, float y, int width, int height); /* axis or -1 */ int sky_gizmo_begin(SkyEngine* engine, float x, float y, int width, int height); /* 1 if a handle was grabbed */ void sky_gizmo_drag(SkyEngine* engine, float x, float y, int width, int height, int snapping);
void sky_gizmo_end(SkyEngine* engine);
void sky_set_view_scene_camera(SkyEngine* engine, int on); 1 = viewport looks through the scene's primary camera, 0 = editor orbit camera.
void sky_camera_angles(SkyEngine* engine, float* yaw, float* pitch); Editor camera state for overlays: yaw, pitch (degrees).
char* sky_frame_stats(SkyEngine* engine); Frame statistics: {"cpuMs":..,"draws":..,"lights":..,"entities":..,"renderer":"..","gpuMs":.., "debugView":"final", "profile":{"supported":bool,"spanMs":..,"passes":[{"pass","group","ms","avgMs","maxMs"}], "groups":{..},"cpu":[{"scope","avgMs","maxMs"}]}} (profile: rolling 60-frame per-pass GPU timing)

Game input (forwarded to Wander while playing)

Declaration Notes
void sky_input_key(SkyEngine* engine, const char* key, int down); /* "w", "space", "shift", ... */ void sky_input_click(SkyEngine* engine, uint64_t entity);
void sky_input_mouse_move(SkyEngine* engine, float x, float y, float dx, float dy); Mouse while playing. x, y: cursor position in the viewport, 0..1 from the top-left. dx, dy: movement since the last call in pixels, +y DOWN as on screen (the engine flips it). button: 0 left, 1 right, 2 middle.
void sky_input_mouse_button(SkyEngine* engine, int button, int down);
void sky_input_scroll(SkyEngine* engine, float dx, float dy);
void sky_input_text(SkyEngine* engine, const char* utf8); Typed characters (UTF-8) for UI text fields; delivered with the next tick.
void sky_input_gamepad(SkyEngine* engine, int index, int connected, const char* name, const SkyGamepad* state);

Gamepads. Call once per frame for every connected controller (index 0..3) and once with connected = 0 when one leaves. Sticks -1..1 with +y up, triggers 0..1. buttons is a bitmask in this order: bit 0 south (A / Cross), 1 east (B / Circle), 2 west (X / Square), 3 north (Y / Triangle), 4 left shoulder, 5 right shoulder, 6 left trigger, 7 right trigger, 8 select, 9 start, 10 left stick click, 11 right stick click, 12-15 dpad up/down/left/right, 16 guide.

typedef struct SkyGamepad {
    float left_x, left_y, right_x, right_y;
    float left_trigger, right_trigger;
    uint32_t buttons;
} SkyGamepad;

Agent server: MCP over a Unix socket so external agents can attach

Declaration Notes
int sky_agent_server_start(SkyEngine* engine, const char* socket_path); socket_path may be NULL for the default (~/.skywalker/editor.sock). Returns 0 on success.
void sky_agent_server_stop(SkyEngine* engine);

Example

#include "sky_api.h"

int main(void) {
    SkyEngine* engine = sky_engine_create("my_game");
    char* result = sky_call_tool(engine, "entity_create",
                                 "{\"name\": \"Crate\", \"mesh\": \"cube\", \"position\": [0, 0.5, 0]}",
                                 "user");
    sky_string_free(result);
    sky_update(engine, 1.0 / 60.0);
    sky_engine_destroy(engine);
    return 0;
}