Build your first plugin
A complete, minimal plugin: one node type that stores a point and a radius, draws itself in plan and 3D, and a command that creates one. Every call below is in the host API reference.
1. The entry point
A plugin is a DLL exporting exactly one symbol. The host calls it once at startup and hands over the function table; you keep the pointer.
#include "yu3d_plugin.h"
static const Yu3dHostApi* H = 0;
YU3D_PLUGIN_EXPORT int yu3d_plugin_register(const Yu3dHostApi* host) {
if (!host || host->abi_version != YU3D_PLUGIN_ABI_VERSION) return 0;
H = host;
register_my_type();
return 1; /* 0 = refuse to load */
}
Returning 0 is the honest failure: a plugin that cannot satisfy its contract must not half-register.
2. Declare the node type
The host owns the document tree; your plugin owns one opaque
payload per node and is called back to (de)serialise, draw
and destroy it.
typedef struct { double x, y, r; } MyCircle;
static void my_write(Yu3dWriter* w, const void* p) {
const MyCircle* c = (const MyCircle*)p;
H->w_f64(w, c->x); H->w_f64(w, c->y); H->w_f64(w, c->r);
}
static void* my_read(Yu3dReader* r) {
MyCircle* c = (MyCircle*)calloc(1, sizeof *c);
if (!H->r_f64(r, &c->x) || !H->r_f64(r, &c->y) || !H->r_f64(r, &c->r)) {
free(c);
return 0; /* short read => fail the node, never guess */
}
return c;
}
static void my_destroy(void* p) { free(p); }
3. Draw it
Plan coordinates are world metres and colours are linear 0…1; the canvas owns zoom and styling. Emit pickable geometry and the host resolves clicks for you.
static void my_plan(Yu3dPlanCtx* ctx, const void* p) {
const MyCircle* c = (const MyCircle*)p;
for (int i = 0; i < 32; ++i) {
double a0 = 6.28318530718 * i / 32.0, a1 = 6.28318530718 * (i + 1) / 32.0;
H->plan_add_segment(ctx,
c->x + c->r * cos(a0), c->y + c->r * sin(a0),
c->x + c->r * cos(a1), c->y + c->r * sin(a1),
0.9f, 0.5f, 0.1f, 1 /* pickable */);
}
}
4. Register the type and a command
static void my_run(Yu3dDocument* doc, void* user) {
MyCircle* c = (MyCircle*)calloc(1, sizeof *c);
c->x = 0; c->y = 0; c->r = 5;
H->doc_add_node(doc, "my.circle", c, "Circle"); /* one undoable edit */
}
static void register_my_type(void) {
Yu3dNodeType t;
memset(&t, 0, sizeof t);
t.type_id = "my.circle";
t.write = my_write;
t.read = my_read;
t.destroy = my_destroy;
t.plan_render = my_plan;
H->register_node_type(&t);
H->register_command("my.circle.create", "Create Circle", "My Plugin",
my_run, 0);
}
5. What you get for free
| Behaviour | Who provides it |
|---|---|
| Undo / redo of your command | host — doc_add_node is one edit |
| Save / load of your node | host frames and versions the payload you write |
| Selection, picking, highlight | host, from the pickable geometry you emit |
| A document opened WITHOUT your plugin | host keeps the bytes verbatim and writes them back — no data loss |
That last row is the point of the design. A colleague without your plugin can open, edit and save the file; your nodes survive untouched and reappear when the plugin is present again.