ofdoc document serialization for the ofxKit stack
README
ofxDocumentKit
ofxKit stack addon for ECS project I/O:
.ofdoc save/load, dirty tracking, and File menu wiring via registerWith(runtime).Component field codecs live in ofxEnTTKit (
json/component_json.h / visitFields). This addon owns the document envelope, id remap, session, and thin OFDOC_REGISTER_COMPONENT binders only.Usage
#include "ofxDocumentKit.h"
ofxDocumentKit::ofxDocumentKit m_docKit;
void ofApp::setup() {
m_docKit.registerWith(runtime());
}Call
m_docKit.session().markDirty() when your app edits the scene. For undo, use runtime().undoStack().push(...) directly (see ofxKit docs/undo.md) and call markDirty() after edits.Multi-page documents: status-bar page tabs (opt out with
enablePageTabs = false) and File → Document Properties list pages. Use setActivePageIndex / addPage / removePage / reorderPage, and setOnActivePageChanged when the host needs to re-bridge paper/canvas after a page switch.Document dirty is session-level unsaved state (
DirtyTracker). Entity/cache invalidate flags use ecs::dirty_component or a plain bool dirty — see ofxKit docs/dirty-state.md.Document prefs (recent files) are stored under
bin/data/.../ofxDocumentKit/documentPrefs.json without changing the app's Runtime data subdir.Example
Build
example-document — a minimal 2D scene with File → New / Open / Save / Save As.Format
.ofdoc is versioned JSON:document— file header fromdocument_metadata_component(name, author, timestamps, format version, active page, page count) pluspaints[](ordered paint entity ids fromecs::paint_library_componenton the metadata entity).entities[]— content entities with component keys registered viaOFDOC_REGISTER_COMPONENT.
ecs::createSolidPaint / ecs::createGradientPaint (or document helpers that also register into the paint library). ofxEnTTInspector edits paints through the same EnTTKit APIs.Speaks Rig
This addon makes openFrameworks a RigWorks fulfillment on the wire.
src/RigCodec. translates between the in-memory .ofdoc shape and the rig.document format — save emits Rig, load sniffs the root and reshapes back, legacy .ofdoc roots skip the codec entirely. Pure JSON to JSON: no openFrameworks, no EnTT, testable standalone (tests/run.ps1). Emitted documents pass rig-validate --strict.Schema ids spoken (fields match the Contract):
| Family | Ids |
|---|---|
rig.spatial. | transform, relationship, group, layer |
rig.geometry. | rectangle, ellipse, line, arc, polygon, regular_polygon, ring, star, path |
rig.paint. | solid, gradient, fill, stroke, library |
rig.meta. / rig.layout. | named, tags, page |
rig.media. | asset_ref, code, text |
rig.mod. | lfo, binding |
rig.music. | clock, transport, sequencer, midi_input, midi_output |
rig.render. | light, material, visibility |
rig.sim. / rig.audio. / rig.interact. | rigidbody, particle_emitter, analysis, selectable |
- Host-only fields of a mapped component travel as
x.ofkitty.<key>carrying only the leftovers — never a duplicate of portable fields, so edits by another Rig host survive a round trip. - Components with no portable meaning travel whole as
x.ofkitty.<key>. Unknownrig.components from foreign documents are dropped on load. - The mapping lives at the IO seam: in-memory PODs in ofxEnTTKit keep their host field names; the codec reshapes on save/load.
Hierarchy
The parent chain is
ecs::Relationship.parent + ecs::LocalTransform. On save/load, ofxDocumentKit round-trips the ECS spatial tree so meshes, layers, and Scene-panel reparenting stay in sync.Registering serializers
Component serializers register through
OFDOC_REGISTER_COMPONENT (see CoreSerializers.cpp and CoreSerializersPhase2.inl). Prefer adding ecs::visitFields + ecs::json::toJson/fromJson in ofxEnTTKit, then a one-line binder here.Registering a serializer also defines which entities are included in save/clear.
Runtime-only types (settings entities,
GlobalTransform, GPU caches, live device handles, postfx / skybox / instanced_mesh) are skipped or never registered.Path members on
filepath, shader, texture, and cubemap are stored relative to the document directory (same helpers as filepath_component). mod_binding round-trips targetEntity / targetKey (and nested bindings on modulator / eased_pulse); the runtime float* target is not serialized — rebind after load.
ofxAddons