Self-contained specification for implementing the xplatter code generation tool.
xplatter generates cross-platform API bindings from a single YAML API definition, targeting Android, iOS, Web, Windows, macOS, and Linux. Implementation language agnostic — any language with C ABI + WASM exports works.
Written in Go — single static binary, trivial cross-compilation.
Prebuilt binaries for:
- x86_64 and arm64 Windows 10+
- arm64 macOS
- x86_64 Linux (statically linked,
CGO_ENABLED=0)
Fallback: build_codegen.sh script + Makefile. Dependencies resolve via Go modules.
xplatter <command> [flags]
Commands:
| Command | Description |
|---|---|
generate |
Generate C ABI header, platform bindings, and impl scaffolding |
validate |
Check API definition and FlatBuffers schemas without generating |
init |
Scaffold a new project with starter API definition and FBS files |
dump_schema |
Print the built-in API definition JSON Schema |
version |
Print version and exit |
Global flags (apply to all commands):
| Flag | Description |
|---|---|
-v, --verbose |
Verbose output |
-q, --quiet |
Suppress all output except errors |
generate flags:
| Flag | Description |
|---|---|
-o, --output <dir> |
Output directory (default: ./generated) |
-f, --flatc <path> |
Path to FlatBuffers compiler |
--impl-lang <lang> |
Override impl_lang from API definition |
--targets <list> |
Override targets (comma-separated) |
--dry-run |
Show what would be generated without writing |
--clean |
Remove previously generated files first |
--skip-flatc |
Skip flatc invocation even if flatc is available (generated bindings will be incomplete) |
validate flags:
| Flag | Description |
|---|---|
-f, --flatc <path> |
Path to FlatBuffers compiler |
init flags:
| Flag | Description |
|---|---|
-n, --name <name> |
API name (default: my_api) |
--impl-lang <lang> |
Implementation language (default: cpp) |
-o, --output <dir> |
Output directory (default: current directory) |
dump_schema flags:
| Flag | Description |
|---|---|
-o, --output <file> |
Write schema to file instead of stdout |
FlatBuffers compiler resolution order:
--flatcflagXPLATTER_FLATC_PATHenvironment variableflatcinPATH
Defines the API surface — handles, interfaces, and methods. Validated against a JSON Schema (Section 13).
Top-level keys:
api: # Required. Metadata.
flatbuffers: # Required. FlatBuffers schema file paths.
handles: # Optional. Opaque handle type definitions.
interfaces: # Required. Grouped method definitions.No additional top-level keys are permitted.
| Field | Required | Type | Constraint |
|---|---|---|---|
name |
yes | string | snake_case: ^[a-z][a-z0-9_]*$. Used as prefix in all C ABI function names. |
version |
yes | string | Semver: ^\d+\.\d+\.\d+$ |
description |
no | string | Human-readable description |
impl_lang |
yes | string | One of: cpp, rust, go, c |
targets |
no | array | Subset of: android, ios, web, windows, macos, linux. If omitted, all targets. |
Array of .fbs file paths (relative to YAML file). At least one required. Types referenced by fully-qualified namespace (e.g., Common.ErrorCode).
| Field | Required | Type | Constraint |
|---|---|---|---|
name |
yes | string | PascalCase: ^[A-Z][a-zA-Z0-9]*$ |
description |
no | string |
Referenced as handle:Name in method signatures.
| Field | Required | Type | Constraint |
|---|---|---|---|
name |
yes | string | snake_case |
description |
no | string | Human-readable description |
constructors |
no | array | Methods that create handles (same structure as methods) |
methods |
no | array | Regular methods |
At least one of constructors or methods must be present. When an interface declares constructors, the code gen tool auto-generates a matching destroy method for the handle returned by the constructor. Constructors are methods that return a handle type, are fallible, and take no handle input parameters.
| Field | Required | Type | Constraint |
|---|---|---|---|
name |
yes | string | snake_case |
description |
no | string | |
parameters |
no | array | Ordered list of parameters |
returns |
no | object | Has a type field and optional description |
error |
no | string | Must be a FlatBuffers enum type reference |
| Field | Required | Type | Constraint |
|---|---|---|---|
name |
yes | string | snake_case |
type |
yes | string | See Section 4 (Type System) |
transfer |
no | string | value (default), ref, or ref_mut |
description |
no | string |
All data types (structs, enums, unions, tables, constants) are defined in .fbs files — the YAML never defines data types. The tool parses .fbs files to resolve type references and invokes flatc for per-language struct codegen.
| Type | C ABI | Size |
|---|---|---|
int8 |
int8_t |
1 byte |
int16 |
int16_t |
2 bytes |
int32 |
int32_t |
4 bytes |
int64 |
int64_t |
8 bytes |
uint8 |
uint8_t |
1 byte |
uint16 |
uint16_t |
2 bytes |
uint32 |
uint32_t |
4 bytes |
uint64 |
uint64_t |
8 bytes |
float32 |
float |
4 bytes |
float64 |
double |
8 bytes |
bool |
bool |
1 byte |
Valid as both parameter and return types. Default transfer: value.
C ABI: const char*, null-terminated, UTF-8. Follows ref semantics implicitly.
Parameter only. Cannot be used as a return type. Return string data via FlatBuffer result types.
Where T is any primitive type. Expands to two C parameters:
const T* data, uint32_t data_len // data_len = element count, NOT byte countTransfer: ref produces const T*, ref_mut produces T*.
Parameter only. Cannot be used as a return type. Return buffer data via FlatBuffer result types.
Opaque handle from the handles section. C ABI: the handle typedef (e.g., engine_handle). Passed by value (pointer copy). transfer not applicable. Valid as both parameter and return types.
Fully-qualified namespace references (e.g., Common.ErrorCode). Must resolve in the included .fbs files. Valid as both parameter and return types; typically use transfer: ref as parameters.
C type name mapping: Dots → underscores (Common.ErrorCode → Common_ErrorCode). Used consistently across all generators.
C header type emission: Full typedef enum/typedef struct definitions for all referenced FlatBuffer types, emitted after handle typedefs and before platform services. Order: enums, then structs, then tables, alphabetically within each category.
| Type | Parameter | Return |
|---|---|---|
| Primitives | yes | yes |
string |
yes | no |
buffer<T> |
yes | no |
handle:Name |
yes | yes |
| FlatBuffer types | yes | yes |
The side that allocates deallocates. No ownership transfer, release callbacks, or ref-counting across the FFI.
| Mode | C ABI | Meaning |
|---|---|---|
value |
Pass by value | Copied. Default for primitives and handles. |
ref |
const T* |
Immutable borrow for call duration. |
ref_mut |
T* |
Mutable borrow for call duration. |
Strictly unidirectional — bound language calls implementation, never the reverse. No function pointers cross the boundary. Reverse communication via shared ring buffer (Section 8).
All state is per-handle. Multiple instances can coexist.
The generated C header ({api_name}.h) has a fixed section ordering:
- Include guard:
#ifndef {UPPER_SNAKE_CASE(api_name)}_H/#define ... - Standard includes:
#include <stdint.h>,#include <stdbool.h> - Symbol visibility export macro (see Section 6.6)
- C++ compatibility:
#ifdef __cplusplus/extern "C" {/#endif - Handle typedefs (if any handles defined)
- FlatBuffer type definitions (enums, then structs, then tables — sorted alphabetically within each category)
- Platform service declarations (no export macro — these are link-time provided)
- Interface method declarations (grouped by interface, prefixed with export macro)
- Closing C++ guard:
#ifdef __cplusplus/}/#endif - Closing include guard:
#endif
Line wrapping: Signatures exceeding 80 characters (including export macro) wrap to multi-line with 4-space indented parameters, one per line.
<api_name>_<interface_name>_<method_name>
Example: API my_engine, interface renderer, method begin_frame:
int32_t my_engine_renderer_begin_frame(renderer_handle renderer);typedef struct <lowercase_name>_s* <lowercase_name>_handle;
// e.g., typedef struct renderer_s* renderer_handle;Methods with error return the error enum (FlatBuffers enum, success = 0). Four patterns:
Fallible, no return value:
int32_t myapi_renderer_begin_frame(renderer_handle renderer);Fallible, with return value (return becomes out-parameter):
int32_t myapi_lifecycle_create_engine(engine_handle* out_result);Infallible, with return value:
uint64_t myapi_scene_get_entity_count(scene_handle scene);Infallible, no return value:
void myapi_lifecycle_destroy_engine(engine_handle engine);A buffer<T> parameter becomes two C parameters: const T* <name>, uint32_t <name>_len (element count). ref_mut produces T* instead of const T*.
string becomes const char* <name> — always UTF-8, null-terminated.
The C header emits a per-API export macro:
/* Symbol visibility */
#if defined(_WIN32) || defined(_WIN64)
#ifdef <UPPER_API_NAME>_BUILD
#define <UPPER_API_NAME>_EXPORT __declspec(dllexport)
#else
#define <UPPER_API_NAME>_EXPORT __declspec(dllimport)
#endif
#elif defined(__GNUC__) || defined(__clang__)
#define <UPPER_API_NAME>_EXPORT __attribute__((visibility("default")))
#else
#define <UPPER_API_NAME>_EXPORT
#endif<UPPER_API_NAME> = API name in UPPER_SNAKE_CASE (e.g., HELLO_XPLATTER).
Rules:
- Emitted after standard includes, before
extern "C"block _BUILDmacro defined by build system when compiling the shared library; consumers getdllimporton Windows- API methods prefixed with
_EXPORT; platform services are NOT (link-time provided) - Macro appears before return type:
MACRO return_type function_name(params) - Rust (
#[no_mangle]+cdylib) and Go (//export+c-shared) handle export natively
| Target | Output |
|---|---|
android |
Kotlin public API + JNI bridge calling C ABI functions |
ios |
Swift public API + C bridge calling C ABI functions |
macos |
Swift public API + C bridge calling C ABI functions |
web |
JavaScript public API + WASM bindings calling C ABI exports |
windows |
C API header (consumed directly or via language-specific FFI) |
linux |
C API header (consumed directly or via language-specific FFI) |
The C API header is always generated regardless of targets. All bindings route through the C ABI — WASM/JS uses C ABI exports (not embind/wasm-bindgen).
Strings use JNI GetStringUTFChars/ReleaseStringUTFChars. Handles are wrapped in Kotlin classes with create/destroy mapped to constructor/close().
Output: {PascalCase(api_name)}.kt + {api_name}_jni.c
Naming:
| Concept | Pattern | Example (api_name: hello_world) |
|---|---|---|
| Kotlin package | {api_name} with _ → . |
hello.world |
| Handle class | {handle.Name} (PascalCase from YAML) |
Engine |
| Singleton object | {PascalCase(api_name)} |
HelloWorld |
| JNI function | Java_{package_path}_{Class}_{method} |
Java_hello_world_Engine_start |
| Error exception | {FlatBufferCType}Exception |
CommonErrorCodeException |
Type mappings:
| xplatter | Kotlin | JNI C |
|---|---|---|
string |
String |
jstring |
buffer<uint8> |
ByteArray |
jbyteArray |
handle:X |
Handle class | jlong |
| Primitives | Int, Long, Float, Boolean |
jint, jlong, jfloat, jboolean |
| FlatBuffer | ByteArray |
jbyteArray |
Method patterns:
- Factory methods (create): return the handle class
- Instance methods: called on handle class, skip the handle parameter (it's
this) - Destroy: mapped to
close()or similar teardown
Strings use withCString or automatic bridging. Handles are wrapped in Swift classes with create/destroy mapped to static factory/deinit.
Output: {PascalCase(api_name)}.swift
Naming:
| Concept | Pattern | Example |
|---|---|---|
| Handle class | {handle.Name} (PascalCase) |
Engine |
| Error enum | {FlatBufferCType}Error: Error |
CommonErrorCodeError |
Type mappings:
| xplatter | Swift |
|---|---|
string |
String (marshalled via withCString) |
buffer<uint8> |
Data / UnsafeMutableBufferPointer<UInt8> |
handle:X |
Handle class |
| Primitives | Int32, UInt64, Bool, Float, Double |
| FlatBuffer | UnsafePointer<Type> / UnsafeMutablePointer<Type> |
Strings use TextEncoder/TextDecoder for WASM linear memory marshalling. Handles are wrapped in JS objects with create/destroy mapped to constructor/dispose().
Output: {api_name}.js (ES module)
Naming:
| Concept | Pattern | Example |
|---|---|---|
| Handle class | {handle.Name} (PascalCase) |
Engine |
| Loader function | load{PascalCase(api_name)} |
loadHelloWorld |
| Method names | {camelCase(method_name)} |
beginFrame |
Patterns:
- Handle classes use
#ptrprivate field, zeroed ondispose() - Buffers: copied into/out of WASM memory via
TypedArray - Fallible methods with return: allocate out-param space in WASM memory, read result via
DataView - Cleanup via
finally { _free(ptr) }for temporaries - Platform services passed as a services object to the loader:
logSink,resourceCount,resourceName,resourceExists,resourceSize,resourceRead
Link-time C functions with fixed signatures, implemented by the platform binding layer. The implementation calls these as plain C functions (WASM imports on web). Not callbacks.
void <api_name>_log_sink(int32_t level, const char* tag, const char* message);Global (not per-handle). Per-platform: Android → android.util.Log, iOS/macOS → os_log, Web → console.* via WASM import, Desktop → stderr.
uint32_t <api_name>_resource_count(void);
int32_t <api_name>_resource_name(uint32_t index, char* buffer, uint32_t buffer_size);
int32_t <api_name>_resource_exists(const char* name);
uint32_t <api_name>_resource_size(const char* name);
int32_t <api_name>_resource_read(const char* name, uint8_t* buffer, uint32_t buffer_size);Per-platform: Android → AssetManager via JNI, iOS/macOS → NSBundle.main, Desktop → filesystem relative to executable, Web → synchronous lookup in pre-loaded in-memory store.
On web, resources need not be fully loaded before WASM initialization — resource_exists returns false and resource_read returns an error for unavailable resources.
Structured FlatBuffer payloads delivered through the event queue polling mechanism, decoupled from logging. The app layer polls and routes to its reporting system.
The implementation communicates back via a shared ring buffer with platform-native signaling: eventfd/pipe() + Looper on Android/Linux, dispatch source on iOS/macOS, Event object on Windows, requestAnimationFrame polling on web main thread, SharedArrayBuffer + Atomics.notify on web Workers.
Controlled by impl_lang. Generates an abstract interface, C ABI shim, and stub implementation per language.
impl_lang |
Abstract Interface | C ABI Shim | Stub Implementation |
|---|---|---|---|
cpp |
Abstract class (pure virtual) | .cpp with virtual dispatch shims |
Concrete class with stubs |
rust |
Trait definition | extern "C" functions → trait impl |
Skeleton impl block |
go |
Interface type | //export cgo → interface impl |
Stub functions |
c |
— | — (impl exports C ABI directly) | Stub .c file with TODO bodies |
All impl_langs additionally generate a Makefile (scaffold) and platform service stubs. With c, there is no abstract interface or shim layer — the implementation exports the C ABI functions directly.
Files are either regenerated (overwritten each run) or scaffold (only written if the file doesn't exist, allowing user customization). Scaffold files are marked with (scaffold) below. Files marked with (project) are written to the parent of the output directory (e.g., for Makefiles that live at the project root).
Always: {api_name}.h (C ABI header)
impl_lang: c — {api_name}_impl.c (scaffold), CMakeLists.txt (scaffold)
impl_lang: cpp — _interface.h (abstract class), _shim.cpp (extern "C" shim), _impl.h + _impl.cpp (scaffold) (concrete stubs + factory), CMakeLists.txt (scaffold)
impl_lang: rust — _trait.rs (traits), _ffi.rs (extern "C" shims), _impl.rs (scaffold) (stubs), _types.rs (if types exist), Cargo.toml (scaffold), src/lib.rs (scaffold)
impl_lang: go — _interface.go (interfaces), _cgo.go (//export shims), _impl.go (scaffold) (stubs), _types.go (if enums exist), go.mod (scaffold), .gitignore (scaffold), and _wasm.go (if web is in targets; //go:wasmexport stubs for GOOS=wasip1 builds)
All impl_langs additionally generate:
Makefile(scaffold, project) — build rules for desktop, iOS, Android, WASM targets with platform detection, MSVC/NDK/Emscripten discovery, and packagingplatform_services/desktop.c(scaffold, project) — logging and resource stubs for desktopplatform_services/ios.c(scaffold, project) — logging viaos_log, resource stubs for iOSplatform_services/android.c(scaffold, project) — logging via__android_log_print, resource stubs for Androidplatform_services/web.c(scaffold, project) — no-op stubs for WASM
Platform bindings: android → {PascalCase}.kt + _jni.c | ios/macos → {PascalCase}.swift | web → {api_name}.js | windows/linux → C header only
flatc is invoked once per required language into flatbuffers/<lang>/ subdirectories, determined by targets and impl_lang:
| Trigger | flatc flag | Output subdirectory | Example output |
|---|---|---|---|
targets includes android |
--kotlin |
flatbuffers/kotlin/ |
{Namespace}/{Type}.kt per type |
targets includes ios or macos |
--swift |
flatbuffers/swift/ |
{schema}_generated.swift |
targets includes web |
--ts |
flatbuffers/ts/ |
{schema}.ts + per-type files |
impl_lang: cpp |
--cpp |
flatbuffers/cpp/ |
{schema}_generated.h |
impl_lang: rust |
--rust |
flatbuffers/rust/ |
{schema}_generated.rs |
impl_lang: go |
--go |
flatbuffers/go/ |
Go package files |
Duplicates are deduplicated (e.g., ios + macos → single --swift). Use --skip-flatc to suppress.
Constructors and destructors are handled deterministically — no heuristic scanning of method names or signatures.
Constructors are explicitly declared in the constructors: field of an interface definition. They are methods that create handles. ConstructorHandleName() on InterfaceDef identifies which handle an interface creates by inspecting the first constructor's return type.
Destructors are auto-synthesized by the code gen tool. When an interface has constructors, SyntheticDestructor() generates a destroy method for that handle (e.g., handle Greeter → method destroy_greeter with a single handle:Greeter parameter). The destroy method is infallible and void.
Shim behavior by language:
- C++ shim: Create methods call
create_{api_name}_instance(), check null, cast to handle, store in*out_result. Destroy methods cast handle back,delete. Regular methods cast handle to interface pointer and delegate. - Rust: All methods (including constructors and destructors) delegate uniformly through trait dispatch (
TraitName::method(&Impl, ...)). No special factory/teardown bodies. - Go: All methods delegate through interface lookup and a handle map. Constructors call
allocHandle(), destructors callfreeHandle(). - Swift and Kotlin bindings: Wire the auto-generated destroy method to
deinit/close()on the handle class.
Naming conventions:
| Concept | Pattern | Example (api_name: hello_world) |
|---|---|---|
| Interface class | {PascalCase(api_name)}Interface |
HelloWorldInterface |
| Impl class | {PascalCase(api_name)}Impl |
HelloWorldImpl |
| Factory function | create_{api_name}_instance() |
create_hello_world_instance() |
| Interface guard | {UPPER_SNAKE_CASE(api_name)}_INTERFACE_H |
HELLO_WORLD_INTERFACE_H |
| Impl guard | {UPPER_SNAKE_CASE(api_name)}_IMPL_H |
HELLO_WORLD_IMPL_H |
Interface type mappings (idiomatic C++, not raw C):
| xplatter Type | C++ Interface Type |
|---|---|
string |
std::string_view |
buffer<T> (ref) |
std::span<const T> |
buffer<T> (ref_mut) |
std::span<T> |
handle:X |
void* (opaque in interface; shim does the cast) |
| Primitives | stdint types (int32_t, float, etc.) |
| FlatBuffer (ref) | const Type* |
| FlatBuffer (ref_mut) | Type* |
Includes: <stdint.h>, <stdbool.h>, <cstddef>, <string_view>, <span>, and "{api_name}.h" for FlatBuffer types.
Shim behavior: Includes C header + interface header. All functions in extern "C" { }, prefixed with _EXPORT.
- Create: Calls
create_{api_name}_instance(), checks null,reinterpret_castto handle, stores in*out_result, returns 0 - Destroy:
reinterpret_casthandle → interface pointer,delete - Regular: Cast handle →
{InterfaceClass}*, wrap strings instring_view(), buffers inspan(), callself->{method}(args). Handle params pass through asvoid*.
Naming conventions:
| Concept | Pattern | Example |
|---|---|---|
| Trait name | {PascalCase(interface_name)} |
Lifecycle, Renderer |
| ZST struct | pub struct Impl; |
(always Impl) |
| Trait impl | impl {TraitName} for Impl |
impl Lifecycle for Impl |
ZST dispatch: All trait methods take &self. A ZST Impl implements all traits. FFI calls via UFCS: Lifecycle::create_greeter(&Impl, ...) — compile-time dispatch, zero overhead.
Trait type mappings:
| xplatter Type | Rust Trait Type | Rust FFI Type |
|---|---|---|
string |
&str |
*const c_char |
buffer<T> (ref) |
&[T] |
*const T, u32 |
buffer<T> (ref_mut) |
&mut [T] |
*mut T, u32 |
handle:X |
*mut c_void |
*mut c_void |
| Primitives | Rust types (i32, u64, bool, f32) |
Same |
| FlatBuffer (ref) | &Type |
*const Type |
| FlatBuffer (ref_mut) | &mut Type |
*mut Type |
FFI function pattern:
#[no_mangle]
pub unsafe extern "C" fn {cabi_function_name}(params) -> i32 {
// Convert: CStr::from_ptr(s).to_str().expect("invalid UTF-8")
// Convert: std::slice::from_raw_parts(ptr, len as usize)
// Convert: &*ptr (for FlatBuffer const ref)
match {TraitName}::{method}(&Impl, converted_args) {
Ok(val) => { *out_result = val; 0 }
Err(e) => e as i32,
}
}Trait methods with error return Result<T, ErrorType>. The FFI shim matches Ok/Err → integer error code.
Naming conventions:
| Concept | Pattern | Example (api_name: hello_world) |
|---|---|---|
| Package name | {api_name} with underscores removed |
helloworld |
| Interface name | {PascalCase(interface_name)} |
Lifecycle, Renderer |
Critical cgo rule: Do NOT #include the generated C header in //export files — conflicting prototypes. Use local typedefs in the cgo preamble:
/*
typedef struct greeter_s* greeter_handle;
typedef struct { const char* message; } Hello_Greeting;
*/
import "C"Handle map: Go cannot pass Go pointers to C; uses an integer handle map instead:
var (
handles sync.Map
nextHandle uintptr
)
func allocHandle(impl interface{}) C.{handle_type} {
h := atomic.AddUintptr(&nextHandle, 1)
handles.Store(h, impl)
return C.{handle_type}(unsafe.Pointer(h))
}
func lookupHandle(h C.{handle_type}) (impl, bool) {
val, ok := handles.Load(uintptr(unsafe.Pointer(h)))
...
}
func freeHandle(h C.{handle_type}) {
handles.Delete(uintptr(unsafe.Pointer(h)))
}//export function pattern:
//export {cabi_function_name}
func {cabi_function_name}(params) C.int32_t {
impl, ok := lookupHandle(handle)
goStr := C.GoString(cStr)
// delegate to impl...
}Go type mappings:
| xplatter Type | Go Interface Type | cgo Type |
|---|---|---|
string |
string |
*C.char |
buffer<T> |
[]T |
*C.{ctype}, C.uint32_t |
handle:X |
uintptr |
C.{handle_typedef} |
| Primitives | Go types (int32, uint64, bool) |
C.int32_t, C.uint64_t, C._Bool |
| FlatBuffer | *C.{Type} |
*C.{Type} |
All shim code is mechanically derivable from the API definition — each method produces one shim function determined entirely by parameter types, transfer semantics, return type, and error convention.
The code gen tool produces source files only. Packaging those into deliverable platform artifacts is a build-system concern handled by Makefiles, Gradle, Xcode projects, etc. See ARCHITECTURE.md for the full provider/consumer model and per-platform package contents.
The provider (library author) runs codegen, implements the interface, and builds platform packages. The consumer (app developer) receives pre-built packages and calls the idiomatic binding — no dependency on xplatter or flatc.
Consumer app projects typically use an ensure-package pattern: check for the pre-built package, and if absent, trigger the provider's package build.
Structural (JSON Schema):
- YAML structure matches schema
- All names follow conventions (snake_case, PascalCase)
- FlatBuffer paths end in
.fbs - Version is semver
impl_langis valid enumtargetsvalues are valid
Semantic (requires .fbs parsing):
- All
handle:Namereferences resolve to handles defined in thehandlessection - All FlatBuffer type references (e.g.,
Common.ErrorCode) resolve to types in the included.fbsfiles errortypes are FlatBuffer enumsstringandbuffer<T>are not used as return typestransferis not specified on handle parameters
api:
name: example_app_engine
version: 0.1.0
description: "Example interactive application engine API"
impl_lang: cpp
targets:
- android
- ios
- web
flatbuffers:
- specs/geometry.fbs
- specs/input_events.fbs
- specs/rendering.fbs
- specs/scene.fbs
- specs/common.fbs
handles:
- name: Engine
- name: Renderer
- name: Scene
- name: Texture
interfaces:
- name: lifecycle
constructors:
- name: create_engine
returns:
type: handle:Engine
error: Common.ErrorCode
# destroy_engine is auto-generated for handle:Engine
- name: renderer
constructors:
- name: create_renderer
parameters:
- name: engine
type: handle:Engine
- name: config
type: Rendering.RendererConfig
transfer: ref
returns:
type: handle:Renderer
error: Common.ErrorCode
# destroy_renderer is auto-generated for handle:Renderer
methods:
- name: begin_frame
parameters:
- name: renderer
type: handle:Renderer
error: Common.ErrorCode
- name: end_frame
parameters:
- name: renderer
type: handle:Renderer
error: Common.ErrorCode
- name: texture
constructors:
- name: load_texture_from_path
parameters:
- name: renderer
type: handle:Renderer
- name: path
type: string
returns:
type: handle:Texture
error: Common.ErrorCode
- name: load_texture_from_buffer
parameters:
- name: renderer
type: handle:Renderer
- name: data
type: buffer<uint8>
- name: format
type: Rendering.TextureFormat
returns:
type: handle:Texture
error: Common.ErrorCode
# destroy_texture is auto-generated for handle:Texture
- name: input
methods:
- name: push_touch_events
parameters:
- name: engine
type: handle:Engine
- name: events
type: Input.TouchEventBatch
transfer: ref
error: Common.ErrorCode
- name: events
methods:
- name: poll_events
parameters:
- name: engine
type: handle:Engine
- name: events
type: Common.EventQueue
transfer: ref_mut
error: Common.ErrorCode#ifndef EXAMPLE_APP_ENGINE_H
#define EXAMPLE_APP_ENGINE_H
#include <stdint.h>
#include <stdbool.h>
/* Symbol visibility */
#if defined(_WIN32) || defined(_WIN64)
#ifdef EXAMPLE_APP_ENGINE_BUILD
#define EXAMPLE_APP_ENGINE_EXPORT __declspec(dllexport)
#else
#define EXAMPLE_APP_ENGINE_EXPORT __declspec(dllimport)
#endif
#elif defined(__GNUC__) || defined(__clang__)
#define EXAMPLE_APP_ENGINE_EXPORT __attribute__((visibility("default")))
#else
#define EXAMPLE_APP_ENGINE_EXPORT
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct engine_s* engine_handle;
typedef struct renderer_s* renderer_handle;
typedef struct scene_s* scene_handle;
typedef struct texture_s* texture_handle;
/* FlatBuffer type definitions (enums, structs, tables) — see Section 6.0 */
/* Platform services — implement these per platform */
void example_app_engine_log_sink(int32_t level, const char* tag, const char* message);
uint32_t example_app_engine_resource_count(void);
int32_t example_app_engine_resource_name(uint32_t index, char* buffer, uint32_t buffer_size);
int32_t example_app_engine_resource_exists(const char* name);
uint32_t example_app_engine_resource_size(const char* name);
int32_t example_app_engine_resource_read(const char* name, uint8_t* buffer, uint32_t buffer_size);
/* lifecycle */
EXAMPLE_APP_ENGINE_EXPORT int32_t example_app_engine_lifecycle_create_engine(
engine_handle* out_result);
EXAMPLE_APP_ENGINE_EXPORT void example_app_engine_lifecycle_destroy_engine(
engine_handle engine); /* auto-generated */
/* renderer */
EXAMPLE_APP_ENGINE_EXPORT int32_t example_app_engine_renderer_create_renderer(
engine_handle engine,
const Rendering_RendererConfig* config,
renderer_handle* out_result);
EXAMPLE_APP_ENGINE_EXPORT void example_app_engine_renderer_destroy_renderer(
renderer_handle renderer); /* auto-generated */
EXAMPLE_APP_ENGINE_EXPORT int32_t example_app_engine_renderer_begin_frame(
renderer_handle renderer);
EXAMPLE_APP_ENGINE_EXPORT int32_t example_app_engine_renderer_end_frame(
renderer_handle renderer);
/* texture */
EXAMPLE_APP_ENGINE_EXPORT int32_t example_app_engine_texture_load_texture_from_path(
renderer_handle renderer,
const char* path,
texture_handle* out_result);
EXAMPLE_APP_ENGINE_EXPORT int32_t example_app_engine_texture_load_texture_from_buffer(
renderer_handle renderer,
const uint8_t* data,
uint32_t data_len,
Rendering_TextureFormat format,
texture_handle* out_result);
EXAMPLE_APP_ENGINE_EXPORT void example_app_engine_texture_destroy_texture(
texture_handle texture); /* auto-generated */
/* input */
EXAMPLE_APP_ENGINE_EXPORT int32_t example_app_engine_input_push_touch_events(
engine_handle engine,
const Input_TouchEventBatch* events);
/* events */
EXAMPLE_APP_ENGINE_EXPORT int32_t example_app_engine_events_poll_events(
engine_handle engine,
Common_EventQueue* events);
#ifdef __cplusplus
}
#endif
#endifFull schema at docs/api_definition_schema.json. Key rules:
api,flatbuffers,interfacesare required top-level keyshandlesis optional- No additional properties at any level
- Parameter types match:
^(int8|...|bool|string|buffer<primitive>|handle:[A-Z]...|[A-Z]Namespace.Type...)$ - Return types exclude
stringandbuffer<T> errormust be a FlatBuffer type referenceimpl_langis one of:cpp,rust,go,ctargetsvalues are from:android,ios,web,windows,macos,linux
Not to be implemented now, but do not foreclose:
- Platform + language pairs —
targetsmay evolve tolinux:python,windows:lua, etc. The C ABI foundation supports this; platform services would need load-time registration for dynamically loaded languages.