For AI
Execution is cheap; agreement is the scarce asset. Load this before generating Rig data, copy the examples rather than inventing a vocabulary, and validate the output.
v0.31.0 · draft llms.txt skill source
Generating Rig documents
When to use
Load this skill when generating or editing Rig entity data, SUDE hooks, or ECS component schemas - or when emitting portable JSON a host should load.
Core model
Rig - Readable Independent Grammar: the schema catalog and portable entity/component POD documents (rig.document). Schemas are optional; ship what you support. Nothing to link into an app. Not another editor. Floor: honors.md.
Live hosts also honor SUDE and runtime ECS conventions (registry, Update/Draw systems). Document composition (entities + POD components) is always required; the loop is not.
Document composition (always)
| Rule | Detail |
|---|---|
| Entities + components | Portable meaning is POD keyed by schema ids |
| POD only | Numbers, small structs, strings, entity ids |
| No portable handles | No GPU/UI toolkit types, callbacks, dirty flags, hover/press, pending queues |
| No derived fields | Hosts may cache winding, world matrices, Euler, bar/beat; do not serialize them - Host cache |
| Hierarchy (optional) | Parent as entity id; local position / rotation (quat) / scale |
SUDE (live hosts)
Setup, Update, Draw, Exit
| Hook | When | Semantics |
|---|---|---|
Setup() |
Once | Allocate app state. May be empty. |
Update(dt) |
Each tick, before Draw | Simulation. dt = seconds (host clock). |
Draw() |
Each tick, after Update | Present. Always called; empty body OK. |
Exit() |
Once, before teardown | Release state. May be empty. |
Do not nest hooks. No display/UI required for SUDE compliance.
Runtime ECS (live hosts)
| Rule | Detail |
|---|---|
| App owns registry | No second hidden registry for app entities |
| Simulate / Present | Mutate in Update; present in Draw |
Semantic versioning
The Contract uses Semantic Versioning (MAJOR.MINOR.PATCH). One source of truth: VERSION. Ranges and History: docs/versioning.md.
| When | Bump |
|---|---|
| Additive schema / optional fields (0.x draft) | MINOR (e.g. 0.9.0 to 0.10.0) |
Breaking schema or core-rule change after 1.0.0 |
MAJOR |
| Docs-only / tooling / no schema meaning change | leave VERSION alone |
When you change schemas: bump VERSION and add a History row in docs/versioning.md (release notes). Do not copy the number into README or other docs. npm run check:version (also the pre-commit hook) only requires VERSION to be SemVer.
When generating a document, set root "rig" to the current VERSION (or an older version the document actually targets - older docs stay valid under additive releases).
Document shape
Wire format is JSON - rig.document. On disk that is a .rig file, or a .rigz ZIP (one .rig at the archive root plus a data/ folder) when sidecar files travel with the document - interchange.
| Root field | Meaning |
|---|---|
rig |
Contract version (MAJOR.MINOR.PATCH SemVer - see VERSION) |
document |
Optional metadata (title, defaultUnit, ...) |
entities |
Array of { id, components } |
id- string, unique within the filecomponents- map keyed by full schema ids (rig.spatial.transform)entity-typed fields - string id ornullvec*/quat- JSON number arrays; quat order x, y, z, w- Enums - kebab-case literals from the schema (
top-left,color-dodge) - Field names - lowerCamelCase, spelled out (
schemas/README.mdField naming); no SVG abbreviations (radiusXnotrx) - Measurements - ratios 0-1; scene lengths in
document.defaultUnit(pageunitmay override); catalog facts SI in the field name; protocol/clock native -schemas/README.mdMeasurements - Serialize only portable fields; omit host caches
- Optional fields have documented defaults - omit what you did not measure rather than inventing a value (an absent
gatemeans 1; an inventedgatelooks like data)
Exact grammar: schemas/json/.
A component key may also be x.<vendor>.<name> - a host component the Contract has not named. Validators carry it unchecked and report it. Do not reach for this when generating documents: if a rig.* id fits, use it, and if none fits, say so rather than inventing an extension. It exists so a host can adopt .rig natively, not so a generator can route around the catalog - rig.document.
Worked examples
Reference documents: examples/minimal-scene.json, examples/lfo-binding.json, examples/ui-panel.json, examples/portable-tool.json, examples/path3d-spline3d.json, examples/cad-boolean.json, examples/story-flow.json, examples/story-frames.json, examples/bim-model.json, examples/bim-bcf.json, examples/bim-ids.json, examples/font-ufo.json, examples/font-var.json, examples/place-address.json, examples/person-contact.json, examples/plant-taxon.json, examples/book-isbn.json, examples/paper-citation.json, examples/art-object.json, examples/commerce-offer.json, examples/legal-agreement.json, examples/calendar-event.json, examples/lights.json, examples/dev-machine.json, examples/dev-hyperv.json, examples/dev-kvm.json, examples/print-fgf.json. Validate before you trust the output.
Entity with shape + paint
{
"id": "demo-rect",
"components": {
"rig.meta.named": {
"name": "demo-rect",
"stableId": "demo-rect"
},
"rig.spatial.transform": {
"position": [
20,
65,
0
],
"rotation": [
0,
0,
0,
1
],
"scale": [
1,
1,
1
]
},
"rig.spatial.relationship": {
"parent": "world"
},
"rig.geometry.rectangle": {
"x": 0,
"y": 0,
"width": 140,
"height": 90,
"cornerRadius": 10
},
"rig.paint.fill_stroke": {
"fillRgba": [
0.25,
0.65,
1,
1
]
},
"rig.interact.selectable": {
"enabled": true
}
}
}
LFO and binding (Update-side)
{
"entities": [
{
"id": "pulse",
"components": {
"rig.meta.named": { "name": "pulse", "stableId": "pulse" },
"rig.mod.lfo": {
"waveform": "sine",
"frequency": 0.5,
"amplitude": 40,
"offset": 120,
"phase": 0
}
}
},
{
"id": "dot",
"components": {
"rig.meta.named": { "name": "dot", "stableId": "dot" },
"rig.spatial.transform": {
"position": [200, 120, 0],
"rotation": [0, 0, 0, 1],
"scale": [1, 1, 1]
}
}
},
{
"id": "bind-y",
"components": {
"rig.mod.binding": {
"source": "pulse",
"target": "dot",
"propertyKey": "position.y",
"depth": 1,
"min": 40,
"max": 280,
"additive": false
}
}
}
]
}
(Wrap entities in a full document with "rig" set to the current VERSION before validating.)
Feedback loop
Never deliver unvalidated Rig JSON.
- Write or edit a
.jsondocument - Validate:
npm run setup
node tools/rig-validate/cli.js path/to/doc.json
- Fix errors at the reported JSON Pointer paths
- Re-run until the CLI prints
ok - Use
--strictto treat unknown schema ids as errors
rig.ui.* panels travel in the same document envelope - validate them like any other schema (examples/ui-panel.json, examples/portable-tool.json). Rig + UI is optional Contract surface (docs/ui.md), not a separate spec.
When bumping the Contract version: edit VERSION and add a History row in docs/versioning.md, then npm run check:version (pre-commit runs the same check after npm run hooks:install).
Before commit / push (CI precheck)
Do not push Contract changes until the same gate as GitHub Actions passes locally.
npm run setup # once per clone / when validate deps change
npm run check # version, schemas, parity, links, snippets, svg, examples, tests
| When | Required |
|---|---|
Edit schemas / tools/gen-schemas.mjs |
npm run check (at least check:schemas - if stale, npm run gen then re-check) |
Edit VERSION / site badges |
npm run check:version |
Any push to master / open a PR |
full npm run check |
Pre-commit (after npm run hooks:install) only runs SemVer. Pre-push runs the same steps as npm run check via node (so Windows Git hooks work without npm on PATH). Agents must run npm run check themselves before git push even if hooks are missing - do not rely on CI to catch schema drift.
Common mistakes / non-requirements
- Do not invent a tagged-union CSG blob - split
rig.cad.*primitives; mesh on a CAD entity is an optional bake - Do not invent
rig.cad.constraintas a tagged union - a numeric datum isrig.cad.dimension; coincident / parallel stay later split ids if they earn a catalog entry - Do not store a parallel edge table on
rig.geometry.mesh- name fillet/chamfer edges as{a,b}vertex pairs - Do not invent
rig.bim.wall/rig.bim.door- userig.bim.classifywithifcClass; geometry on cad / mesh; typed params onrig.bim.pset - Do not invent
rig.ros2.*- ROS 2 maps onto existing spatial / I/O / sensor / SUDE; TF istransform+relationship; do not put ROS nodes onrig.node.*; see docs/ros.md - Do not invent
rig.font.ttfor growrig.media.textwith outlines - UFO source isrig.font.*; contours composerig.geometry.path; features composerig.media.code(languagefea);.ufois fulfillment - docs/ufo.md - Do not invent
rig.idml.*or graphic frames / object styles / text wrap / GREP / footnotes / variables - IDML maps ontorig.layout.frame+ existing layout / story;.idmlis fulfillment - docs/idml.md - Do not invent
rig.print.gcodeor put host paths / last-slice status onrig.print.job- FGF isrig.print.machine/material/process/compression; files composerig.media.asset_ref; not envelopepdfX, notrig.dev.machine, not a layout page - docs/print.md - Do not put text-frame bounds on
rig.geometry.rectangle- that is a drawable; the box isrig.layout.framewidth/heightplus transform - Do not parent a
rig.story.flowto a page when frames exist - thread viarig.layout.frame_chain - Do not invent schema ids or use PascalCase keys (
Transform,Shape) - component keys are fullrig.*ids; see docs/interchange.md - Do not inline binary blobs or data URIs for files that travel with the document - put them in
data/and save as.rigz;asset_ref.pathis relative todata/ - Do not use
x.<vendor>.<name>to stand in for a catalog id you could not find - report the gap instead - Do not nest SUDE hooks or skip calling
Draw(when authoring a live host) - Do not re-declare
nameon domain schemas - composerig.meta.named - Do not put page/entity origin on
rig.layout.pageor transform - composerig.spatial.anchor(point3×3 face + optionalheightmin/center/max for 3×3×3; absent = no remap / page trim top-left). Origin is a cell offset - never axis invert. Not a locator: that isrig.spatial.vertex. Notrig.font.anchor. - Do not put postal / civic fields or WGS84 on
rig.spatial.transform- composerig.place.addressandrig.place.geo - Do not put given / family name on
rig.meta.named- composerig.person.name;named.nameis the formatted / full name - Do not put sex, birthday, or email on
rig.person.name- composerig.person.vitalandrig.person.contact - Do not copy
sexintogender- recorded sex is ISO/IEC 5218; gender identity is a separate string - Do not put job title, department, or organisation name on
rig.person.contact- composerig.person.employment(employer is an entity) - Do not put a photo path on a person schema - compose
rig.person.portraitwithrig.media.asset_ref - Do not put IBAN / BIC on a person name schema - compose
rig.party.account - Do not put postal fields on a person schema - compose
rig.place.address - Do not put a
scientificNameblob onrig.plant.taxon- composerig.meta.named; parts stay on taxon - Do not put cultivar / Group / grex / trade name on
rig.plant.taxon- composerig.plant.cultivar - Do not put Darwin Core
habitatonrig.plant.habit- habit is growth form; the site isrig.place.geo/rig.place.address - Do not put a photo path on a plant schema - compose
rig.plant.portraitwithrig.media.asset_ref - Do not put a hyphenated ISBN or a title string on
rig.book.identifier- digits-onlyisbn13; distinctive title isrig.meta.named - Do not put author or publisher name strings on a book schema - compose
rig.book.contribution(person entity) andrig.book.publication.publisher(organisation entity) - Do not put a cover path on a book schema - compose
rig.book.coverwithrig.media.asset_ref - Do not put ISBN on a paper - compose
rig.paper.identifier(DOI / PMID / arXiv); journal ISSN stays on the journal entity - Do not store a formatted bibliography string - compose
rig.paper.citation(citing/citedentities) - Do not put copyright holder or licence on
rig.art.objectorrig.book.publication- composerig.rights.statement - Do not put artist name, medium, or centimetres on
rig.art.object- composeattribution,material,dimensions(millimetres) - Do not put a price string or list+sale pair on a book / art schema - compose
rig.commerce.priceon an offer; a discount isrig.commerce.discount - Do not invent a cart, checkout, or tax engine - offer + price + discount +
rig.calendar.spanis the commercial record - Do not put party name strings on
rig.legal.agreement- composerig.legal.party(person / organisation entities) - Do not put copyright of a work on
rig.legal.agreement- that isrig.rights.statement; a licence deal isagreement.kindlicence - Do not copy
jobTitleonto an employment instrument - job facts stay onrig.person.employment - Do not encode iCalendar
RRULE/DTSTART/ATTENDEEstrings - composerig.calendar.event/recurrence/attendee; times arestartMinutesindocument.timeZone - Do not invent
rig.calendar.todo,alarm,freebusy, ortimezone- those stay in the.icssource - Do not put an event title or location string on
rig.calendar.event- composerig.meta.namedandrig.place.address - Do not put show/hide on
rig.spatial.layer- composerig.render.visibility - Do not use
rig.spatial.groupas the world root - that is an unparentedrig.spatial.vertex(a scene) - Do not invent
rig.spatial.sceneor tag vertex withkind- the graph is the tag - Do not put
x/y/zonrig.spatial.vertex- pose stays onrig.spatial.transform - Do not invent
rig.geometry.vertexor indexrig.geometry.meshpositionsvia a vertex component - mesh corners stay packed arrays - Do not put blend / opacity on
rig.pixel.layer- composerig.render.blend - Do not put stroke caps / joins / dash on
rig.paint.fill_stroke- composerig.paint.stroke_style - Do not put text colour on
rig.media.text- compose paint (fill_stroke/fill) - Do not flatten editorial copy into
rig.media.text- that is a canvas run; stories arerig.story.*(named styles, no font or colour) - Do not put bold, italic, underline, strike, super/sub, font, size, or colour on
rig.story.*- a run istext+ style identity; unstyled local emphasis becomes a named character style - SUDE does not require a window, GPU, UI pack, filesystem, or audio
- Being Rig does not require SUDE - only live hosts do - or implementing every schema
- Being Rig does require entity/component POD composition against schemas you support
Vocabulary index
Field meaning: schemas/. Machine grammar: schemas/json/<id>.schema.json.
| Domain | Schema ids |
|---|---|
| Document | rig.document |
| Spatial | transform, anchor, relationship, vertex, group, camera, layer |
| Layout | page, master, applied_master, facing, paragraph_style, character_style, frame, frame_chain |
| Place | address, geo |
| Person | name, vital, contact, employment, portrait |
| Organisation | identity |
| Party | account |
| Commerce | price, offer, discount |
| Plant | taxon, cultivar, habit, occurrence, portrait |
| Book | identifier, title, publication, contribution, cover, subject |
| Paper | identifier, article, issue, citation |
| Rights | statement |
| Legal | agreement, party |
| Art | object, creation, attribution, dimensions, material, location, subject, image |
| Geometry | mesh, path, path3d, rectangle, ellipse, line, polygon, regular_polygon, star, arc, spline, spline3d, nurbs_surface, ring |
| Cad | cuboid, cylinder, sphere, extrude, revolve, boolean, fillet, chamfer |
| Bim | classify, type, occurrence, pset, site, building, storey, space, relation, topic, comment, viewpoint, spec, facet |
| Paint | solid, gradient, fill_stroke, fill, stroke, stroke_style, library |
| Meta / render | named, tags, light, material, visibility, blend |
| Anim / mod | tween, curve, lfo, binding, trigger |
| Music | transport, clock, sequencer, pattern, arrangement, step, note, midi_output, midi_input |
| Audio | analysis, bus |
| Media | asset_ref, text, code |
| Font | face, glyph, component, anchor, layer, kern, group |
| Story | flow, paragraph, paragraph_style, character_style, table |
| Pixel | canvas, source, layer, raster, palette, tile_set, tile_map, effect_chain |
machine, material, process, compression, job |
|
| I/O | osc, serial, sacn, dmx, led.uv_map, sensor.gpio, sensor.presence |
| Dmx | fixture |
| Light | look |
| Calendar | weekly, span, exception, event, recurrence, attendee |
| Sim | rigidbody, particle_emitter |
| Input | buttons |
| Interact | selectable |
| UI | panel, group, control, action |
| Node | graph, node, pin, link, param, publish |
Prefix every component key with rig.<domain>. (e.g. rig.spatial.transform).
Where output goes
RigKit is the reference host. Emit Contract JSON (rig.* keys).