# at.margin.annotation

> Published by [margin.at](https://lexicon.garden/identity/did:plc:rjqn3agdb74cszhqcpii4sne)

✓ This is the authoritative definition for this NSID.

## Description

W3C Web Annotation Data Model compliant annotation record for ATProto

## Links

- [View on Lexicon Garden](https://lexicon.garden/lexicon/did:plc:rjqn3agdb74cszhqcpii4sne/at.margin.annotation)
- [Documentation](https://lexicon.garden/lexicon/did:plc:rjqn3agdb74cszhqcpii4sne/at.margin.annotation/docs)
- [Examples](https://lexicon.garden/lexicon/did:plc:rjqn3agdb74cszhqcpii4sne/at.margin.annotation/examples)

## Definitions

### `at.margin.annotation#body`

**Type**: `object`

Annotation body - the content of the annotation

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `uri` | `string` (uri) | No | Reference to external body content |
| `value` | `string` | No | Text content of the annotation |
| `format` | `string` | No | MIME type of the body content |
| `language` | `string` | No | BCP47 language tag |

### `at.margin.annotation`

**Type**: `record`

A W3C-compliant web annotation stored on the AT Protocol

**Key**: `tid`

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `body` | `ref` → `#body` | No | The annotation content (text or reference) |
| `tags` | `array` | No | Tags for categorization |
| `labels` | `ref` → `com.atproto.label.defs#selfLabels` | No | Self-applied content labels for this annotation |
| `rights` | `string` (uri) | No | License URI (e.g., https://creativecommons.org/licenses/by/4.0/) |
| `target` | `ref` → `#target` | Yes | The resource being annotated with optional selector |
| `createdAt` | `string` (datetime) | Yes |  |
| `generator` | `ref` → `#generator` | No | The client/agent that created this record |
| `motivation` | `string` | No | W3C motivation for the annotation |

### `at.margin.annotation#target`

**Type**: `object`

W3C SpecificResource - the target with optional selector

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `state` | `ref` → `#timeState` | No | State of the resource at annotation time |
| `title` | `string` | No | Page title at time of annotation |
| `source` | `string` (uri) | Yes | The URL being annotated |
| `selector` | `union` | No | Selector to identify the specific segment |
| `sourceHash` | `string` | No | SHA256 hash of normalized URL for indexing |

### `at.margin.annotation#generator`

**Type**: `object`

The client/agent that created this record

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `id` | `string` (uri) | No |  |
| `name` | `string` | No |  |
| `homepage` | `string` (uri) | No |  |

### `at.margin.annotation#timeState`

**Type**: `object`

W3C TimeState - record when content was captured

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `cached` | `string` (uri) | No | URL to cached/archived version |
| `sourceDate` | `string` (datetime) | No | When the source was accessed |

### `at.margin.annotation#cssSelector`

**Type**: `object`

W3C CssSelector - select DOM elements by CSS selector

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | `string` | No |  |
| `value` | `string` | Yes | CSS selector string |

### `at.margin.annotation#rangeSelector`

**Type**: `object`

W3C RangeSelector - select range between two selectors

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | `string` | No |  |
| `endSelector` | `union` | Yes | Selector for range end |
| `startSelector` | `union` | Yes | Selector for range start |

### `at.margin.annotation#xpathSelector`

**Type**: `object`

W3C XPathSelector - select by XPath expression

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | `string` | No |  |
| `value` | `string` | Yes | XPath expression |

### `at.margin.annotation#fragmentSelector`

**Type**: `object`

W3C FragmentSelector - select by URI fragment

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | `string` | No |  |
| `value` | `string` | Yes | Fragment identifier value |
| `conformsTo` | `string` (uri) | No | Specification the fragment conforms to |

### `at.margin.annotation#textQuoteSelector`

**Type**: `object`

W3C TextQuoteSelector - select text by quoting it with context

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | `string` | No |  |
| `exact` | `string` | Yes | The exact text to match |
| `prefix` | `string` | No | Text immediately before the selection |
| `suffix` | `string` | No | Text immediately after the selection |

### `at.margin.annotation#textPositionSelector`

**Type**: `object`

W3C TextPositionSelector - select by character offsets

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `end` | `integer` | Yes | Ending character position (exclusive) |
| `type` | `string` | No |  |
| `start` | `integer` | Yes | Starting character position (0-indexed, inclusive) |

## Raw Schema

```json
{
  "id": "at.margin.annotation",
  "defs": {
    "body": {
      "type": "object",
      "properties": {
        "uri": {
          "type": "string",
          "format": "uri",
          "description": "Reference to external body content"
        },
        "value": {
          "type": "string",
          "maxLength": 10000,
          "description": "Text content of the annotation",
          "maxGraphemes": 3000
        },
        "format": {
          "type": "string",
          "default": "text/plain",
          "description": "MIME type of the body content"
        },
        "language": {
          "type": "string",
          "description": "BCP47 language tag"
        }
      },
      "description": "Annotation body - the content of the annotation"
    },
    "main": {
      "key": "tid",
      "type": "record",
      "record": {
        "type": "object",
        "required": [
          "target",
          "createdAt"
        ],
        "properties": {
          "body": {
            "ref": "#body",
            "type": "ref",
            "description": "The annotation content (text or reference)"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 64,
              "maxGraphemes": 32
            },
            "maxLength": 10,
            "description": "Tags for categorization"
          },
          "labels": {
            "ref": "com.atproto.label.defs#selfLabels",
            "type": "ref",
            "description": "Self-applied content labels for this annotation"
          },
          "rights": {
            "type": "string",
            "format": "uri",
            "description": "License URI (e.g., https://creativecommons.org/licenses/by/4.0/)"
          },
          "target": {
            "ref": "#target",
            "type": "ref",
            "description": "The resource being annotated with optional selector"
          },
          "createdAt": {
            "type": "string",
            "format": "datetime"
          },
          "generator": {
            "ref": "#generator",
            "type": "ref",
            "description": "The client/agent that created this record"
          },
          "motivation": {
            "type": "string",
            "description": "W3C motivation for the annotation",
            "knownValues": [
              "commenting",
              "highlighting",
              "bookmarking",
              "tagging",
              "describing",
              "linking",
              "replying",
              "editing",
              "questioning",
              "assessing"
            ]
          }
        }
      },
      "description": "A W3C-compliant web annotation stored on the AT Protocol"
    },
    "target": {
      "type": "object",
      "required": [
        "source"
      ],
      "properties": {
        "state": {
          "ref": "#timeState",
          "type": "ref",
          "description": "State of the resource at annotation time"
        },
        "title": {
          "type": "string",
          "maxLength": 500,
          "description": "Page title at time of annotation"
        },
        "source": {
          "type": "string",
          "format": "uri",
          "description": "The URL being annotated"
        },
        "selector": {
          "refs": [
            "#textQuoteSelector",
            "#textPositionSelector",
            "#cssSelector",
            "#xpathSelector",
            "#fragmentSelector",
            "#rangeSelector"
          ],
          "type": "union",
          "description": "Selector to identify the specific segment"
        },
        "sourceHash": {
          "type": "string",
          "description": "SHA256 hash of normalized URL for indexing"
        }
      },
      "description": "W3C SpecificResource - the target with optional selector"
    },
    "generator": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "format": "uri"
        },
        "name": {
          "type": "string"
        },
        "homepage": {
          "type": "string",
          "format": "uri"
        }
      },
      "description": "The client/agent that created this record"
    },
    "timeState": {
      "type": "object",
      "properties": {
        "cached": {
          "type": "string",
          "format": "uri",
          "description": "URL to cached/archived version"
        },
        "sourceDate": {
          "type": "string",
          "format": "datetime",
          "description": "When the source was accessed"
        }
      },
      "description": "W3C TimeState - record when content was captured"
    },
    "cssSelector": {
      "type": "object",
      "required": [
        "value"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "CssSelector"
        },
        "value": {
          "type": "string",
          "maxLength": 2000,
          "description": "CSS selector string"
        }
      },
      "description": "W3C CssSelector - select DOM elements by CSS selector"
    },
    "rangeSelector": {
      "type": "object",
      "required": [
        "startSelector",
        "endSelector"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "RangeSelector"
        },
        "endSelector": {
          "refs": [
            "#textQuoteSelector",
            "#textPositionSelector",
            "#cssSelector",
            "#xpathSelector"
          ],
          "type": "union",
          "description": "Selector for range end"
        },
        "startSelector": {
          "refs": [
            "#textQuoteSelector",
            "#textPositionSelector",
            "#cssSelector",
            "#xpathSelector"
          ],
          "type": "union",
          "description": "Selector for range start"
        }
      },
      "description": "W3C RangeSelector - select range between two selectors"
    },
    "xpathSelector": {
      "type": "object",
      "required": [
        "value"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "XPathSelector"
        },
        "value": {
          "type": "string",
          "maxLength": 2000,
          "description": "XPath expression"
        }
      },
      "description": "W3C XPathSelector - select by XPath expression"
    },
    "fragmentSelector": {
      "type": "object",
      "required": [
        "value"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "FragmentSelector"
        },
        "value": {
          "type": "string",
          "maxLength": 1000,
          "description": "Fragment identifier value"
        },
        "conformsTo": {
          "type": "string",
          "format": "uri",
          "description": "Specification the fragment conforms to"
        }
      },
      "description": "W3C FragmentSelector - select by URI fragment"
    },
    "textQuoteSelector": {
      "type": "object",
      "required": [
        "exact"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "TextQuoteSelector"
        },
        "exact": {
          "type": "string",
          "maxLength": 5000,
          "description": "The exact text to match",
          "maxGraphemes": 1500
        },
        "prefix": {
          "type": "string",
          "maxLength": 500,
          "description": "Text immediately before the selection",
          "maxGraphemes": 150
        },
        "suffix": {
          "type": "string",
          "maxLength": 500,
          "description": "Text immediately after the selection",
          "maxGraphemes": 150
        }
      },
      "description": "W3C TextQuoteSelector - select text by quoting it with context"
    },
    "textPositionSelector": {
      "type": "object",
      "required": [
        "start",
        "end"
      ],
      "properties": {
        "end": {
          "type": "integer",
          "minimum": 0,
          "description": "Ending character position (exclusive)"
        },
        "type": {
          "type": "string",
          "const": "TextPositionSelector"
        },
        "start": {
          "type": "integer",
          "minimum": 0,
          "description": "Starting character position (0-indexed, inclusive)"
        }
      },
      "description": "W3C TextPositionSelector - select by character offsets"
    }
  },
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1,
  "revision": 2,
  "description": "W3C Web Annotation Data Model compliant annotation record for ATProto"
}
```
