/spec/annotation/v2/) at a new URL, leaving this version permanently resolvable for files that reference it. The format is under active development and may gain further optional members within version 1; see §10.
This document specifies the JSON-LD document that MeshNotes produces and consumes as its native annotation format. A MeshNotes export is a single
W3C Web Annotation Data Model [WADM] AnnotationCollection that gathers the annotations placed on one 3D model, together with the description of that model, the annotation groups, optional model-level notes, and an optional structured metadata report.
The format is W3C Web Annotation at its core, extended in two controlled ways. First, the geometry of each annotation is identified by a MeshNotes 3D selector, defined in the companion MeshNotes 3D Selector Specification [SEL]; that document is normative for everything inside an annotation's selector, including the coordinate frame, WKT notation, CRS handling and model-binding hash, and is not repeated here. Second, MeshNotes-specific information that the W3C model does not cover is carried under the meshnotes: namespace, resolved through the JSON-LD context at https://meshnotes.org/ns/context-v1.jsonld.
The design goal is interoperability: a consumer that understands only the W3C Web Annotation Data Model can read every annotation, its target, its bodies and its grouping, and ignore the meshnotes: extensions; a consumer that understands the extensions additionally recovers the full editing state for a faithful round-trip. The format is designed to be cleanly mappable to CIDOC CRM and ingestible by infrastructure such as NFDI4Objects, though it emits neither RDF nor LIDO directly in this version.
| Prefix | IRI |
|---|---|
meshnotes: | https://meshnotes.org/ns/ |
oa: | http://www.w3.org/ns/oa# |
dcterms: | http://purl.org/dc/terms/ |
schema: | https://schema.org/ |
geo: | http://www.opengis.net/ont/geosparql# |
xsd: | http://www.w3.org/2001/XMLSchema# |
A document conforms to this specification when:
AnnotationCollection carrying the members marked must in §3;"dcterms:conformsTo": "https://meshnotes.org/spec/annotation/v1/" at the collection level;Annotation whose target.selector conforms to [SEL];https://meshnotes.org/ns/context-v1.jsonld;https://meshnotes.org/spec/annotation/v1/schema.json.
A few coordinate-frame and identity terms — upAxis, unit, annotationType, surfaceProjection — are intentionally exposed without the meshnotes: prefix (the context aliases them) so that non-JSON-LD consumers can read them as plain keys; all MeshNotes-implementation-specific members retain the prefix. A consumer should tolerate either the aliased or the fully-qualified meshnotes: form of these terms.
The key words must, must not, should, should not and may are used as defined in RFC 2119.
The document root is a W3C AnnotationCollection ([WADM] §3.3) holding a single embedded AnnotationPage. Its members:
| Member | Req. | Type | Description |
|---|---|---|---|
@context | must | array | The W3C Web Annotation context followed by the MeshNotes context: ["http://www.w3.org/ns/anno.jsonld", "https://meshnotes.org/ns/context-v1.jsonld"]. |
type | must | string | The literal "AnnotationCollection". |
id | must | IRI | Collection identifier, of the form urn:meshnotes:collection:{uuid}. |
label | should | string | Human-readable label, e.g. "MeshNotes: skyphos.glb". |
dcterms:conformsTo | must | IRI | This specification's URL. Identifies the annotation-format version, independent of the producing application's version. |
generator | may | object | The producing software: { "type": "Software", "name", "schema:version", "homepage" }. |
generated | should | xsd:dateTime | Export timestamp (ISO 8601). |
modelSource | should | object | Canonical description of the annotated model; see §4. |
stylesheet | may | object | An oa:CssStylesheet giving each group its colour; see §7. |
meshnotes:groups | may | array | Group definitions; see §7. |
modelInfo | may | object | Free-text notes about the whole model; see §8. |
metadata | may | object | Structured meta- and paradata report; see §8. |
total | must | integer | Number of annotations in the collection. |
first | must | object | An AnnotationPage: { "type": "AnnotationPage", "items": [ Annotation, ... ] }. |
{
"@context": [
"http://www.w3.org/ns/anno.jsonld",
"https://meshnotes.org/ns/context-v1.jsonld"
],
"type": "AnnotationCollection",
"id": "urn:meshnotes:collection:7b1f…",
"label": "MeshNotes: skyphos.glb",
"dcterms:conformsTo": "https://meshnotes.org/spec/annotation/v1/",
"generator": { "type": "Software", "name": "MeshNotes",
"schema:version": "1.1.0", "homepage": "https://meshnotes.org" },
"generated": "2026-06-08T09:14:00.000Z",
"modelSource": { … },
"stylesheet": { "type": "CssStylesheet", "value": ".group-1 { color: #EDC040; }" },
"meshnotes:groups": [ … ],
"modelInfo": { … },
"metadata": { … },
"total": 12,
"first": { "type": "AnnotationPage", "items": [ … ] }
}
modelSource is the single canonical description of the annotated model. Every annotation's target.source references the same model by the same id, so the coordinate frame, unit and integrity hash are stated once, here.
| Member | Req. | Type | Description |
|---|---|---|---|
id | must | IRI | urn:meshnotes:model:{filename}. The same value appears in each target.source.id. |
type | should | string | "Dataset" (schema.org). |
schema:name | should | string | Model file name. |
format | should | string | Media type of the model (e.g. model/gltf-binary). |
upAxis | should | string | Coordinate up-axis of the exported coordinates. MeshNotes always emits "Z". See [SEL] §3. |
unit | may | string | Real-world linear unit of the coordinates (e.g. "m", "cm", "mm"). Omitted when the producer has no declared unit; a consumer should not assume one when absent. |
meshnotes:crs | may | IRI | OGC CRS URI when the model is georeferenced; governs the georeferenced selector form in [SEL] §3.3. |
schema:sha256 | should | string | SHA-256 hex digest of the canonical model file, binding annotations (and face hints, [SEL] §5) to this exact mesh. Omitted when not available. |
"modelSource": {
"id": "urn:meshnotes:model:skyphos.glb",
"type": "Dataset",
"schema:name": "skyphos.glb",
"format": "model/gltf-binary",
"upAxis": "Z",
"unit": "cm",
"schema:sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
}
Each entry in first.items is a standard W3C Annotation.
| Member | Req. | Type | Description |
|---|---|---|---|
type | must | string | "Annotation". |
id | must | IRI | urn:meshnotes:annotation:{uuid}. The UUID is persistent and is the merge key for collaborative round-trips. |
target | must | object | A SpecificResource; see §5.1. |
motivation | should | string | "tagging" for surface regions, otherwise "describing". |
schema:name | should | string | Annotation name. |
created | should | xsd:dateTime | Creation timestamp. |
modified | may | xsd:dateTime | Last-modified timestamp, when the annotation has more than one entry. |
body | may | array | Zero or more TextualBody entries; see §6. |
annotationType | should | string | One of point, line, polygon, surface, box. Redundant with, but more convenient than, inspecting the selector type. |
meshnotes:groupUuid | may | string | UUID of the group this annotation belongs to (see §7). This is the durable group reference. |
surfaceProjection | may | boolean | Emitted as false only when surface projection is disabled for a line/polygon; absence means the default (projected). |
meshnotes:nameVersions | may | array | Prior values of the annotation name, each { "value", "meshnotes:savedAt" }. |
meshnotes:groupVersions | may | array | Prior group assignments, each { "groupId", "meshnotes:savedAt" }. groupId is a producer-internal reference and is not a durable identifier. |
The target is an oa:SpecificResource whose source references the model and whose selector identifies the geometry.
| Member | Req. | Type | Description |
|---|---|---|---|
type | must | string | "SpecificResource". |
source | must | object | Reference to the model: { "id", "type": "Dataset", "format" }. id equals modelSource.id. |
selector | must | object | A MeshNotes 3D selector conforming to [SEL]. |
styleClass | may | string | CSS class linking to the group colour in the collection stylesheet, e.g. "group-1". |
{
"type": "Annotation",
"id": "urn:meshnotes:annotation:3c9a…",
"motivation": "describing",
"schema:name": "Handle attachment scar",
"created": "2026-06-08T09:10:11.000Z",
"annotationType": "point",
"meshnotes:groupUuid": "b2e1…",
"target": {
"type": "SpecificResource",
"source": { "id": "urn:meshnotes:model:skyphos.glb",
"type": "Dataset", "format": "model/gltf-binary" },
"styleClass": "group-1",
"selector": {
"type": "meshnotes:PointSelector",
"dcterms:conformsTo": "https://meshnotes.org/spec/selector/v1/",
"meshnotes:wkt": "POINT Z (12.4 -3.15 8.02)"
}
},
"body": [ … ]
}
Each observation on an annotation is one oa:TextualBody in the body array. Multiple bodies represent multiple entries (e.g. from different contributors) on the same feature.
| Member | Req. | Type | Description |
|---|---|---|---|
type | must | string | "TextualBody". |
value | must | string | The description text. |
format | should | string | "text/plain". |
language | may | string | BCP-47 language tag of value. Omitted when unknown; a consumer should not assume a language when absent. |
creator | may | object | The author; see §6.1. |
created | may | xsd:dateTime | Entry timestamp. |
modified | may | xsd:dateTime | Entry last-modified timestamp. |
schema:url | may | array | External links attached to the entry. |
meshnotes:entryUuid | should | string | Persistent UUID of the entry; the merge key for entry-level round-trips. |
meshnotes:versions | may | array | Prior states of the entry; see §6.2. |
creator identifies the author of an entry as a person.
| Member | Req. | Type | Description |
|---|---|---|---|
type | should | string | "Person". |
name | should | string | Author display name. |
id | may | IRI | An ORCID URI (https://orcid.org/0000-…) identifying the author. Asserted only when known to belong to that author. |
"creator": {
"id": "https://orcid.org/0009-0003-7750-2818",
"type": "Person",
"name": "Nils Schnorr"
}
Because id maps to @id in the W3C Web Annotation context, the ORCID URI is a first-class node identifier for the author — the conventional, interoperable way to attach an ORCID to a Web Annotation creator, and a clean attachment point for a CIDOC CRM E21 Person mapping.
Each element of meshnotes:versions records a superseded state of the entry, oldest to newest, as { "value", "creator" (optional), "schema:url" (optional), "meshnotes:savedAt" }. This preserves the edit history for accountability in collaborative documentation.
Annotations are organised into named, colour-coded groups. Group definitions are carried in meshnotes:groups; each annotation references its group by UUID (meshnotes:groupUuid), and group colours are also expressed as an oa:CssStylesheet so that a generic W3C consumer can render them via each target's styleClass.
| Member | Req. | Type | Description |
|---|---|---|---|
id | should | number | Producer-internal group id; matches the styleClass suffix and the stylesheet selector. Not a durable identifier. |
meshnotes:uuid | should | string | Persistent group UUID; the value referenced by meshnotes:groupUuid on annotations. |
schema:name | should | string | Group name. |
schema:color | should | string | Group colour (CSS hex). |
meshnotes:visible | may | boolean | Group visibility state. |
meshnotes:opacity | may | number | Group opacity, 0.0–1.0. |
modelInfo carries free-text notes about the model as a whole. It is shaped as a W3C Annotation with "motivation": "describing" and a body array of TextualBody entries identical in structure to §6, but it has no geometric target — it describes the model rather than a region of it.
metadata carries the structured meta- and paradata report (project, capture, reference, processing, paradata and legal information). Its internal field structure is producer-defined and is treated as an open object by this version of the format; a consumer may preserve it verbatim on round-trip and should not reject unknown members within it. A future version may give this block a normative schema and a CIDOC CRM / LIDO crosswalk.
All geometric coordinates in this format — within selectors and their embedded points — follow the coordinate frame, WKT notation, CRS rules, rotation convention and model-binding hash defined normatively in [SEL] §3 and §5. In summary: coordinates are Z-up and right-handed in the model's local frame; the up-axis and unit are declared on modelSource (§4); face identifiers in surface selectors are a non-authoritative hint valid only against the mesh identified by modelSource.schema:sha256.
The format is deliberately open. A conforming consumer must ignore members it does not recognise rather than reject the document, and should preserve them on round-trip where feasible. Within version 1, MeshNotes may add further optional members (in the meshnotes: namespace, or as context-aliased plain keys) without a version bump; it will not add new required members, remove members, or change the meaning of an existing member within version 1. The accompanying JSON Schema (§12) is correspondingly lenient: it validates the required core and the shape of known members, and permits additional properties.
The term namespace https://meshnotes.org/ns/ is unversioned and append-only: identifiers, once published, keep their meaning permanently, and new terms are only ever added. This specification, its JSON Schema, the companion JSON-LD context and the selector specification are versioned and frozen: a breaking change is published at a new version path and the prior version remains resolvable indefinitely, so that files referencing it continue to validate.
A document can be validated structurally against the JSON Schema at https://meshnotes.org/spec/annotation/v1/schema.json (JSON Schema draft 2020-12). The schema is forward-compatible: it checks the required members of the collection, the model description, annotations, targets, selectors and bodies, applies light pattern checks to WKT and identifier strings, and otherwise permits additional properties. Semantic rules that JSON Schema cannot express — polygon ring closure, quaternion normalisation, the hint status of face identifiers — are stated normatively in [SEL] and are not enforced by the schema.
Person, Dataset, sha256, name, color, url, version).