Skip to main content

Native-C API Reference

This page documents the public native-c ABI exposed to plugins. It is based on the current Core runtime behavior and is meant for authors using the public SDK packages, not for authors reading Skydimo source code.

Use the SDK package from Skydimo-Team/Skydimo-SDK that matches your manifest abi.

ABI Model

Native-c plugins are in-process shared libraries. Core loads the library declared by manifest.json entry, looks up skydimo_plugin_get_api, and asks the plugin to fill a function table.

SKYDIMO_EXPORT int32_t skydimo_plugin_get_api(
uint32_t requested_abi_version,
const SkydimoHostApiV1* host,
SkydimoPluginApiV1* out_api);
ItemValue
Current ABI version3
Supported version range2..3
Generic ABI idskydimo-native-c-v3
Effect ABI idskydimo-effect-c-v3
Controller ABI idskydimo-controller-c-v3
Extension ABI idskydimo-extension-c-v3

out_api->abi_version must equal requested_abi_version. out_api->kind_mask must include the API family used by the manifest type.

MaskMeaning
SKYDIMO_PLUGIN_KIND_EFFECTProvides SkydimoEffectApiV1
SKYDIMO_PLUGIN_KIND_CONTROLLERProvides SkydimoControllerApiV1
SKYDIMO_PLUGIN_KIND_EXTENSIONProvides SkydimoExtensionApiV1

Status Conventions

Function kindSuccessSoft resultFailure
Lifecycle callbacks returning int32_t0 or positiveSome callbacks treat 0 as false and positive as trueNegative status
validate and is_readyPositive means true0 means falseNegative status
Read/write callbacks returning intptr_tNon-negative byte count0 means no data or throttled writeNegative status
call_json0 means response writtenPositive means response buffer too small and required_len was setNegative status with error JSON when possible

Never throw exceptions, panic, or unwind through any native-c ABI function. Catch language runtime failures inside the plugin and return a negative status.

Common Types

TypePurpose
SkydimoStrUTF-8 string slice: const char* ptr, size_t len; not null-terminated
SkydimoRgbRGB color with uint8_t r, g, b
SkydimoRgbFrameV1Width, height, and host-owned RGB pixel slice
SkydimoAudioFrameV1Audio amplitude plus FFT bin slice
SkydimoOutputDefinitionV1Controller output metadata and capabilities
SkydimoOutputFrameV1Output id plus RGB color slice
SkydimoHardwareCandidateV1Serial or HID candidate matched from the controller manifest
SkydimoDeviceInfoV1Controller-provided device identity

Pointers passed from Core are valid only for the duration documented by the callback. If a plugin needs data later, it must copy it.

Device Types

Native constants map to device type strings used elsewhere in the plugin APIs:

light, motherboard, dram, gpu, cooler, led_strip, keyboard, mouse,
mouse_mat, headset, headset_stand, gamepad, speaker, virtual, storage,
case, microphone, accessory, keypad, laptop, monitor, unknown

Segment Types

ConstantMeaning
SKYDIMO_SEGMENT_SINGLESingle color zone
SKYDIMO_SEGMENT_LINEARLinear LED strip
SKYDIMO_SEGMENT_MATRIX2D LED matrix
SKYDIMO_SEGMENT_PRESETPreset or non-addressable zone

Plugin API Table

SkydimoPluginApiV1 is the top-level table returned by skydimo_plugin_get_api.

FieldRequiredNotes
sizeYesSet to sizeof(SkydimoPluginApiV1)
abi_versionYesMust equal requested_abi_version
kind_maskYesOR of SKYDIMO_PLUGIN_KIND_*
effectFor effect pluginsSkydimoEffectApiV1 table
controllerFor controller pluginsSkydimoControllerApiV1 table
extensionFor extension pluginsSkydimoExtensionApiV1 table
shutdown_pluginOptionalCalled when Core unloads the loaded plugin wrapper

Host API Table

Core passes SkydimoHostApiV1 to plugin create callbacks. All plugin types receive common callbacks.

CallbackAvailable toPurpose
logAll plugin typesWrite a plugin-scoped log entry
get_plugin_idAll plugin typesReturn the current plugin id as SkydimoStr
call_jsonEffect, controller, extensionLanguage-neutral host method call

call_json Protocol

call_json receives a method name and a UTF-8 JSON request. It writes a UTF-8 JSON response into the provided buffer.

int32_t (*call_json)(
void* host_ctx,
const char* method_ptr,
size_t method_len,
const char* request_ptr,
size_t request_len,
uint8_t* response_ptr,
size_t response_len,
size_t* required_len);

Recommended usage:

  1. Call with a reasonably sized response buffer.
  2. If the return value is positive, allocate required_len bytes and call again.
  3. If the return value is negative, parse the response as { "error": "..." } when a response was written.

request_ptr == NULL or request_len == 0 is treated as JSON null.

Byte JSON Shape

Several call_json methods accept bytes in any of these forms:

{ "bytes": [1, 2, 255] }
{ "data": { "base64": "AQD/" } }
{ "data": "plain UTF-8 text" }

Byte responses include:

{
"bytes": [1, 2, 255],
"base64": "AQL/",
"len": 3
}

Effect Plugin API

Core creates one native effect instance per active effect assignment.

CallbackRequiredCalled when
create(host, out_instance)YesEffect instance is created
destroy(instance)OptionalEffect instance is dropped
resize(instance, width, height, led_count)OptionalTarget LED layout changes
update_params_json(instance, ptr, len)OptionalEffect params change
tick(instance, elapsed_seconds, buffer, len)OptionalEach render frame
is_ready(instance)OptionalCore checks whether async resources are ready

tick receives a mutable RGB buffer owned by Core. Fill the buffer in place; do not store the pointer.

Core consumes internal runtime parameters such as __screen_index, __screen_region, __audio_device_index, and __audio_settings before forwarding params to update_params_json.

Effect Host Callbacks

CallbackPermissionReturn
effect_audio_capture(avg_size, out_frame)audio:capturePositive if data exists, 0 if no frame, negative on error
effect_screen_capture(width, height, out_frame)screen:capturePositive if data exists, 0 if unavailable, negative on error
effect_album_art(width, height, out_frame)media:album_artPositive if data exists, 0 if unavailable, negative on error

Returned frame slices are host-owned and valid until the next related host capture call or until the callback returns to Core.

Effect call_json Methods

MethodPermissionRequestResponse
hsv_to_rgb or host.hsv_to_rgbNone{ "h": 0..360, "s": 0..1, "v": 0..1 }{ "r": 0..255, "g": 0..255, "b": 0..255, "rgb": [r,g,b] }
screen.list_displays or list_displaysscreen:capturenullDisplay list
screen.capture or capture_screenscreen:capture{ "width": n, "height": n }{ "width": n, "height": n, "pixels": [0xRRGGBB...] } or null
audio.capture or capture_audioaudio:capture{ "avg_size": n }, a number, or null{ "amplitude": n, "bins": [...] } or null
media.album_art or album_artmedia:album_art{ "width": n, "height": n }{ "width": n, "height": n, "pixels": [0xRRGGBB...] } or null

Controller Plugin API

Controller plugins are created only for hardware candidates matched by the manifest match rules.

CallbackRequiredCalled when
create(host, candidate, out_instance)YesA serial or HID candidate matched
destroy(instance)OptionalController is dropped
validate(instance)OptionalHandshake; positive accepts, 0 rejects candidate
init(instance)OptionalRegister outputs and perform initialization
get_device_info(instance, out_info)OptionalCore refreshes device identity
get_output_count(instance)OptionalCore reads output definitions from plugin
get_output(instance, index, out_output)OptionalCore reads one output definition
update(instance, frames, frame_count)OptionalNew LED colors are available
set_output_leds_count(instance, output_id, len, count)OptionalUser changes editable LED count
update_output(instance, output)OptionalUser changes output layout
disconnect(instance)OptionalDevice is being disconnected

Controllers can either push device/output metadata through host callbacks during init, or expose get_device_info, get_output_count, and get_output.

Controller Host Callbacks

CallbackPurpose
controller_set_device_info(info)Override manufacturer, model, serial id, device type, image URL, controller id/name, and device path
controller_add_output(output)Register or replace an output definition
controller_output_led_count(output_id)Return current LED count for an output
controller_get_rgb_bytes(output_id, out, out_len)Copy RGB bytes for the latest frame
controller_write(data, data_len)Write to serial or primary HID transport
controller_read(out, out_len, timeout_ms)Read from serial or primary HID transport
controller_hid_send_feature_report(data, data_len)Send HID feature report on primary HID transport
controller_hid_get_feature_report(out, out_len, report_id)Read HID feature report on primary HID transport

Controller call_json Methods

MethodPermissionRequestResponse
system or system.infosystem:infonullSystem information object
hid_interfaces or controller.hid_interfacesNonenullArray of { interface_number, port_key, primary }
hid_write or controller.hid_writeNone{ "data": bytes, "selector": selector }{ "written": n }
hid_read or controller.hid_readNone{ "len": n, "timeout_ms": n, "selector": selector }Byte response
hid_send_feature_report or controller.hid_send_feature_reportNone{ "data": bytes, "selector": selector }{ "written": n }
hid_get_feature_report or controller.hid_get_feature_reportNone{ "len": n, "report_id": n, "selector": selector }Byte response
register_setting, controller.register_setting, or controller.register_config_paramNoneSetting schema{ "ok": true }
get_settings or controller.get_settingsNonenullCurrent settings object
trigger_setting_action or controller.trigger_setting_actionNone{ "key": "setting_key" }{ "ok": true }

selector can be an interface number, a port_key string, or an object such as { "interface_number": 1 } or { "port_key": "..." }.

Extension Plugin API

Extensions run on a Core-managed thread and receive events from device frame delivery, UI page messages, plugin broadcasts, and scan requests.

CallbackRequiredCalled when
create(host, out_instance)YesExtension thread starts
destroy(instance)OptionalExtension is dropped
start(instance)OptionalAfter creation, before event loop
stop(instance)OptionalExtension is stopping
on_scan_devices(instance)OptionalUser or Core requests a device scan
on_event_json(instance, event, data)OptionalExtension broadcast event arrives
on_page_message_json(instance, ptr, len)OptionalExtension page sends a message
on_device_frame(instance, port, frames, frame_count)OptionalSubscribed device frame arrives

Extension Host Callbacks

CallbackPurpose
extension_lock_leds(port, output_id, indices, locked_count, rejected_count)Lock LEDs for extension ownership
extension_unlock_leds(port, output_id, indices)Release LED locks
extension_set_leds_rgb(port, output_id, colors)Set colors for already locked LEDs

Extension call_json Methods

AreaMethods
Plugin info and pathsplugin.info, data_dir, plugin.data_dir, resource_dir, plugin.resource_dir
Systemsystem, system.info, list_system_state_topics, get_system_state
Page and notificationspage_emit, notify, notify_persistent, dismiss_persistent
Devicesregister_device, remove_extension_device, get_devices, get_device_info, set_device_nickname, set_output_leds_count, update_output
LED lockslock_leds, unlock_leds, set_leds, get_led_locks
Effects and resourcesget_effects, get_effect_params, get_displays, get_audio_devices, get_media_session, get_current_media
Scope stateget_scope_screen_state, get_scope_audio_device_state, set_scope_screen_index, set_scope_screen_region, set_scope_audio_device_index
Scope controlset_scope_effect, set_effect, update_scope_effect_params, reset_scope_effect_params, set_scope_mode_paused, set_scope_power, set_scope_brightness
TCPtcp_connect, net.tcp.connect, tcp_write, tcp_send, net.tcp.write, tcp_write_all, net.tcp.write_all, tcp_read, tcp_recv, net.tcp.read, tcp_read_exact, tcp_recv_exact, net.tcp.read_exact, tcp_close, net.tcp.close
HTTPhttp_request, net.http.request, http_open, http_stream, net.http.stream, http_read, net.http.read, http_close, net.http.close
Processspawn_process, is_process_alive, kill_process
HIDhid_enumerate, hid_open, hid_open_path, hid_write, hid_read, hid_send_feature_report, hid_get_feature_report, hid_close

Extension Permissions

CapabilityRequired permission
system / system.infosystem:info
Media session methodsmedia:session
TCP methodsnetwork:tcp or network
HTTP methodsnetwork:http or network
Process methodsprocess
HID methodshardware:hid
System process statesystem:process
System window focus statesystem:window-focus

Common Extension Request Shapes

Scope methods accept a scope either at the top level or under scope:

{
"scope": {
"port": "device-port",
"output_id": "out1",
"segment_id": "segment-a"
}
}

segment_id requires output_id. output_id and segment_id are optional for device-level operations.

register_device accepts:

{
"controller_port": "extension.unique-device",
"manufacturer": "Example",
"model": "Virtual Matrix",
"serial_id": "001",
"device_type": "virtual",
"outputs": [
{
"id": "main",
"name": "Main",
"output_type": "matrix",
"leds_count": 64,
"matrix": { "width": 8, "height": 8, "map": [0, 1, 2] },
"editable": true,
"min_total_leds": 1,
"max_total_leds": 256
}
]
}

lock_leds, unlock_leds, and set_leds use:

{
"port": "device-port",
"output_id": "main",
"indices": [0, 1, 2],
"colors": [
{ "index": 0, "r": 255, "g": 0, "b": 0 },
[0, 255, 0]
]
}

set_leds accepts either { index, r, g, b } entries or RGB arrays. RGB arrays use the array index as the LED index.

Safety Rules

  • Set every ABI table size field to the SDK struct size.
  • Validate requested_abi_version before writing out_api.
  • Copy strings or slices if they must outlive the callback.
  • Keep host callbacks on the thread where Core invoked the plugin unless the SDK explicitly documents otherwise.
  • Do not block high-frequency callbacks such as effect tick or controller update.
  • Treat call_json as a control path, not a bulk data path.
  • Return negative statuses on failure and log useful context through host->log.