# page.corvus.drawing

> Published by [corvus.page](https://lexicon.garden/identity/did:plc:3qc4cbzcriye72qqqodeda26)

✓ This is the authoritative definition for this NSID.

## Description

A drawing block — a vector image composed of shapes that render onto an HTML canvas 2D context. The drawing's `shapes` sequence holds shape block ids in z-order (later = on top). Each shape variant below is its own block. Coordinates are integer pixels; an editor that needs sub-pixel precision can scale its working coord space.

## Links

- [View on Lexicon Garden](https://lexicon.garden/lexicon/did:plc:3qc4cbzcriye72qqqodeda26/page.corvus.drawing)
- [Documentation](https://lexicon.garden/lexicon/did:plc:3qc4cbzcriye72qqqodeda26/page.corvus.drawing/docs)
- [Examples](https://lexicon.garden/lexicon/did:plc:3qc4cbzcriye72qqqodeda26/page.corvus.drawing/examples)

## Definitions

### `page.corvus.drawing`

**Type**: `object`

A drawing canvas containing an ordered sequence of shapes

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `title` | `ref` → `page.corvus.core#sequence` | No | The name of the drawing |
| `width` | `ref` → `page.corvus.core#register` | No | The canvas width in pixels |
| `height` | `ref` → `page.corvus.core#register` | No | The canvas height in pixels |
| `shapes` | `ref` → `page.corvus.core#sequence` | No | The shapes in the drawing as a sequence of shape block ids in z-order (later = on top) |
| `blockId` | `string` (at-uri) | Yes | The AT-URI of this block record |
| `background` | `ref` → `page.corvus.core#register` | No | The canvas background as a CSS color string; omitted or empty for transparent |

### `page.corvus.drawing#path`

**Type**: `object`

A vector path — a sequence of commands that map directly to canvas path operations. Commands are inline values in the sequence and have no stable identity across edits (editing a command means deleting and re-inserting it). Use #stroke instead for freehand brush traces.

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `x` | `ref` → `page.corvus.core#register` | No | Origin X offset applied to the path at render time (defaults to 0) |
| `y` | `ref` → `page.corvus.core#register` | No | Origin Y offset applied to the path at render time (defaults to 0) |
| `fill` | `ref` → `page.corvus.core#register` | No | Fill style as a CSS color string; omitted or empty for no fill |
| `stroke` | `ref` → `page.corvus.core#register` | No | Stroke style as a CSS color string; omitted or empty for no stroke |
| `blockId` | `string` (at-uri) | Yes | The AT-URI of this block record |
| `opacity` | `ref` → `page.corvus.core#register` | No | Opacity from 0 to 1 (defaults to 1) |
| `commands` | `ref` → `page.corvus.core#sequence` | No | The path commands as an RGA sequence of #pathCommand objects |
| `rotation` | `ref` → `page.corvus.core#register` | No | Rotation in radians applied around (x, y) at render time (defaults to 0) |
| `strokeWidth` | `ref` → `page.corvus.core#register` | No | Stroke width in pixels (defaults to 1) |

### `page.corvus.drawing#rect`

**Type**: `object`

An axis-aligned rectangle, optionally rotated around its center

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `x` | `ref` → `page.corvus.core#register` | No | Top-left X coordinate in pixels |
| `y` | `ref` → `page.corvus.core#register` | No | Top-left Y coordinate in pixels |
| `fill` | `ref` → `page.corvus.core#register` | No | Fill style as a CSS color string; omitted or empty for no fill |
| `width` | `ref` → `page.corvus.core#register` | No | Width in pixels |
| `height` | `ref` → `page.corvus.core#register` | No | Height in pixels |
| `stroke` | `ref` → `page.corvus.core#register` | No | Stroke style as a CSS color string; omitted or empty for no stroke |
| `blockId` | `string` (at-uri) | Yes | The AT-URI of this block record |
| `opacity` | `ref` → `page.corvus.core#register` | No | Opacity from 0 to 1 (defaults to 1) |
| `rotation` | `ref` → `page.corvus.core#register` | No | Rotation in radians around the rect's center (defaults to 0) |
| `strokeWidth` | `ref` → `page.corvus.core#register` | No | Stroke width in pixels (defaults to 1) |
| `cornerRadius` | `ref` → `page.corvus.core#register` | No | Corner radius in pixels (defaults to 0) |

### `page.corvus.drawing#text`

**Type**: `object`

A text label rendered with canvas fillText/strokeText

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `x` | `ref` → `page.corvus.core#register` | No | Anchor X coordinate in pixels |
| `y` | `ref` → `page.corvus.core#register` | No | Anchor Y coordinate in pixels (text baseline) |
| `fill` | `ref` → `page.corvus.core#register` | No | Fill style as a CSS color string; omitted or empty for no fill |
| `text` | `ref` → `page.corvus.core#sequence` | No | The text content as a text sequence (editable per-character) |
| `align` | `ref` → `page.corvus.core#register` | No | Horizontal alignment relative to (x, y) — 'left', 'center', or 'right' (defaults to 'left') |
| `stroke` | `ref` → `page.corvus.core#register` | No | Stroke style as a CSS color string; omitted or empty for no stroke |
| `weight` | `ref` → `page.corvus.core#register` | No | Font weight as a CSS font-weight value |
| `blockId` | `string` (at-uri) | Yes | The AT-URI of this block record |
| `opacity` | `ref` → `page.corvus.core#register` | No | Opacity from 0 to 1 (defaults to 1) |
| `fontSize` | `ref` → `page.corvus.core#register` | No | Font size in pixels |
| `rotation` | `ref` → `page.corvus.core#register` | No | Rotation in radians around (x, y) (defaults to 0) |
| `fontFamily` | `ref` → `page.corvus.core#register` | No | Font family as a CSS font-family string |
| `strokeWidth` | `ref` → `page.corvus.core#register` | No | Stroke width in pixels (defaults to 0) |

### `page.corvus.drawing#group`

**Type**: `object`

A named collection of shape block ids — a tag that lets a set of shapes be referred to together (selected, named, toggled). Membership is order-independent; z-order comes from #main.shapes

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `name` | `ref` → `page.corvus.core#register` | No | The display name of the group |
| `shapes` | `ref` → `page.corvus.core#set` | No | The set of member shape block ids |
| `blockId` | `string` (at-uri) | Yes | The AT-URI of this block record |

### `page.corvus.drawing#image`

**Type**: `object`

A placed image — positions and sizes a page.corvus.contentBlocks#image within the drawing. The image asset itself lives in the referenced block (its blob, alt text, and aspect ratio); this variant only carries the placement

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `x` | `ref` → `page.corvus.core#register` | No | Top-left X coordinate in pixels |
| `y` | `ref` → `page.corvus.core#register` | No | Top-left Y coordinate in pixels |
| `image` | `ref` → `page.corvus.core#register` | No | Register whose value is the at-uri of the page.corvus.contentBlocks#image block to render |
| `width` | `ref` → `page.corvus.core#register` | No | Width in pixels |
| `height` | `ref` → `page.corvus.core#register` | No | Height in pixels |
| `blockId` | `string` (at-uri) | Yes | The AT-URI of this block record |
| `opacity` | `ref` → `page.corvus.core#register` | No | Opacity from 0 to 1 (defaults to 1) |
| `rotation` | `ref` → `page.corvus.core#register` | No | Rotation in radians around the image's center (defaults to 0) |

### `page.corvus.drawing#stroke`

**Type**: `object`

A freehand stroke — a brush trace captured atomically. Sample points are written once as a single register value; individual points are not edited collaboratively. To redo the stroke, replace the points register

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `x` | `ref` → `page.corvus.core#register` | No | Origin X offset applied to the stroke at render time (defaults to 0) |
| `y` | `ref` → `page.corvus.core#register` | No | Origin Y offset applied to the stroke at render time (defaults to 0) |
| `color` | `ref` → `page.corvus.core#register` | No | Brush color as a CSS color string |
| `width` | `ref` → `page.corvus.core#register` | No | Brush width in pixels (base width if pressure modulates) |
| `points` | `ref` → `page.corvus.core#register` | No | The stroke's samples as a single register whose value is an array of #strokePoint objects |
| `blockId` | `string` (at-uri) | Yes | The AT-URI of this block record |
| `opacity` | `ref` → `page.corvus.core#register` | No | Opacity from 0 to 1 (defaults to 1) |
| `rotation` | `ref` → `page.corvus.core#register` | No | Rotation in radians applied around (x, y) at render time (defaults to 0) |

### `page.corvus.drawing#ellipse`

**Type**: `object`

An ellipse or circle (set rx == ry for a circle)

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `cx` | `ref` → `page.corvus.core#register` | No | Center X coordinate in pixels |
| `cy` | `ref` → `page.corvus.core#register` | No | Center Y coordinate in pixels |
| `rx` | `ref` → `page.corvus.core#register` | No | X radius in pixels |
| `ry` | `ref` → `page.corvus.core#register` | No | Y radius in pixels |
| `fill` | `ref` → `page.corvus.core#register` | No | Fill style as a CSS color string; omitted or empty for no fill |
| `stroke` | `ref` → `page.corvus.core#register` | No | Stroke style as a CSS color string; omitted or empty for no stroke |
| `blockId` | `string` (at-uri) | Yes | The AT-URI of this block record |
| `opacity` | `ref` → `page.corvus.core#register` | No | Opacity from 0 to 1 (defaults to 1) |
| `rotation` | `ref` → `page.corvus.core#register` | No | Rotation in radians around (cx, cy) (defaults to 0) |
| `strokeWidth` | `ref` → `page.corvus.core#register` | No | Stroke width in pixels (defaults to 1) |

### `page.corvus.drawing#pathCommand`

**Type**: `object`

A single path command. Used inline as a value in a #path.commands sequence — NOT its own block, NOT addressable, no stable identity across edits

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `op` | `string` | Yes | M=moveTo (x,y); L=lineTo (x,y); C=bezierCurveTo (cp1x,cp1y,cp2x,cp2y,x,y); Q=quadraticCurveTo (cpx,cpy,x,y); A=arc (cx,cy,r,startAngle,endAngle,counterclockwise); Z=closePath (no coords) |
| `coords` | `array` | No | Coordinate arguments; interpretation depends on op. Angles for the A command are encoded in milliradians (0 to 2π × 1000) so they fit an integer |

### `page.corvus.drawing#strokePoint`

**Type**: `object`

A single sample within a #stroke. Used inline as an element of #stroke.points

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `x` | `integer` | Yes | X coordinate in pixels |
| `y` | `integer` | Yes | Y coordinate in pixels |
| `pressure` | `integer` | No | Optional pen pressure, 0-255 (0 = lift, 255 = max) |

## Raw Schema

```json
{
  "id": "page.corvus.drawing",
  "defs": {
    "main": {
      "type": "object",
      "required": [
        "blockId"
      ],
      "properties": {
        "title": {
          "ref": "page.corvus.core#sequence",
          "type": "ref",
          "description": "The name of the drawing"
        },
        "width": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "The canvas width in pixels"
        },
        "height": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "The canvas height in pixels"
        },
        "shapes": {
          "ref": "page.corvus.core#sequence",
          "type": "ref",
          "description": "The shapes in the drawing as a sequence of shape block ids in z-order (later = on top)"
        },
        "blockId": {
          "type": "string",
          "format": "at-uri",
          "description": "The AT-URI of this block record"
        },
        "background": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "The canvas background as a CSS color string; omitted or empty for transparent"
        }
      },
      "description": "A drawing canvas containing an ordered sequence of shapes"
    },
    "path": {
      "type": "object",
      "required": [
        "blockId"
      ],
      "properties": {
        "x": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Origin X offset applied to the path at render time (defaults to 0)"
        },
        "y": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Origin Y offset applied to the path at render time (defaults to 0)"
        },
        "fill": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Fill style as a CSS color string; omitted or empty for no fill"
        },
        "stroke": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Stroke style as a CSS color string; omitted or empty for no stroke"
        },
        "blockId": {
          "type": "string",
          "format": "at-uri",
          "description": "The AT-URI of this block record"
        },
        "opacity": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Opacity from 0 to 1 (defaults to 1)"
        },
        "commands": {
          "ref": "page.corvus.core#sequence",
          "type": "ref",
          "description": "The path commands as an RGA sequence of #pathCommand objects"
        },
        "rotation": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Rotation in radians applied around (x, y) at render time (defaults to 0)"
        },
        "strokeWidth": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Stroke width in pixels (defaults to 1)"
        }
      },
      "description": "A vector path — a sequence of commands that map directly to canvas path operations. Commands are inline values in the sequence and have no stable identity across edits (editing a command means deleting and re-inserting it). Use #stroke instead for freehand brush traces."
    },
    "rect": {
      "type": "object",
      "required": [
        "blockId"
      ],
      "properties": {
        "x": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Top-left X coordinate in pixels"
        },
        "y": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Top-left Y coordinate in pixels"
        },
        "fill": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Fill style as a CSS color string; omitted or empty for no fill"
        },
        "width": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Width in pixels"
        },
        "height": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Height in pixels"
        },
        "stroke": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Stroke style as a CSS color string; omitted or empty for no stroke"
        },
        "blockId": {
          "type": "string",
          "format": "at-uri",
          "description": "The AT-URI of this block record"
        },
        "opacity": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Opacity from 0 to 1 (defaults to 1)"
        },
        "rotation": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Rotation in radians around the rect's center (defaults to 0)"
        },
        "strokeWidth": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Stroke width in pixels (defaults to 1)"
        },
        "cornerRadius": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Corner radius in pixels (defaults to 0)"
        }
      },
      "description": "An axis-aligned rectangle, optionally rotated around its center"
    },
    "text": {
      "type": "object",
      "required": [
        "blockId"
      ],
      "properties": {
        "x": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Anchor X coordinate in pixels"
        },
        "y": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Anchor Y coordinate in pixels (text baseline)"
        },
        "fill": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Fill style as a CSS color string; omitted or empty for no fill"
        },
        "text": {
          "ref": "page.corvus.core#sequence",
          "type": "ref",
          "description": "The text content as a text sequence (editable per-character)"
        },
        "align": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Horizontal alignment relative to (x, y) — 'left', 'center', or 'right' (defaults to 'left')"
        },
        "stroke": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Stroke style as a CSS color string; omitted or empty for no stroke"
        },
        "weight": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Font weight as a CSS font-weight value"
        },
        "blockId": {
          "type": "string",
          "format": "at-uri",
          "description": "The AT-URI of this block record"
        },
        "opacity": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Opacity from 0 to 1 (defaults to 1)"
        },
        "fontSize": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Font size in pixels"
        },
        "rotation": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Rotation in radians around (x, y) (defaults to 0)"
        },
        "fontFamily": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Font family as a CSS font-family string"
        },
        "strokeWidth": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Stroke width in pixels (defaults to 0)"
        }
      },
      "description": "A text label rendered with canvas fillText/strokeText"
    },
    "group": {
      "type": "object",
      "required": [
        "blockId"
      ],
      "properties": {
        "name": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "The display name of the group"
        },
        "shapes": {
          "ref": "page.corvus.core#set",
          "type": "ref",
          "description": "The set of member shape block ids"
        },
        "blockId": {
          "type": "string",
          "format": "at-uri",
          "description": "The AT-URI of this block record"
        }
      },
      "description": "A named collection of shape block ids — a tag that lets a set of shapes be referred to together (selected, named, toggled). Membership is order-independent; z-order comes from #main.shapes"
    },
    "image": {
      "type": "object",
      "required": [
        "blockId"
      ],
      "properties": {
        "x": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Top-left X coordinate in pixels"
        },
        "y": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Top-left Y coordinate in pixels"
        },
        "image": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Register whose value is the at-uri of the page.corvus.contentBlocks#image block to render"
        },
        "width": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Width in pixels"
        },
        "height": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Height in pixels"
        },
        "blockId": {
          "type": "string",
          "format": "at-uri",
          "description": "The AT-URI of this block record"
        },
        "opacity": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Opacity from 0 to 1 (defaults to 1)"
        },
        "rotation": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Rotation in radians around the image's center (defaults to 0)"
        }
      },
      "description": "A placed image — positions and sizes a page.corvus.contentBlocks#image within the drawing. The image asset itself lives in the referenced block (its blob, alt text, and aspect ratio); this variant only carries the placement"
    },
    "stroke": {
      "type": "object",
      "required": [
        "blockId"
      ],
      "properties": {
        "x": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Origin X offset applied to the stroke at render time (defaults to 0)"
        },
        "y": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Origin Y offset applied to the stroke at render time (defaults to 0)"
        },
        "color": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Brush color as a CSS color string"
        },
        "width": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Brush width in pixels (base width if pressure modulates)"
        },
        "points": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "The stroke's samples as a single register whose value is an array of #strokePoint objects"
        },
        "blockId": {
          "type": "string",
          "format": "at-uri",
          "description": "The AT-URI of this block record"
        },
        "opacity": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Opacity from 0 to 1 (defaults to 1)"
        },
        "rotation": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Rotation in radians applied around (x, y) at render time (defaults to 0)"
        }
      },
      "description": "A freehand stroke — a brush trace captured atomically. Sample points are written once as a single register value; individual points are not edited collaboratively. To redo the stroke, replace the points register"
    },
    "ellipse": {
      "type": "object",
      "required": [
        "blockId"
      ],
      "properties": {
        "cx": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Center X coordinate in pixels"
        },
        "cy": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Center Y coordinate in pixels"
        },
        "rx": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "X radius in pixels"
        },
        "ry": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Y radius in pixels"
        },
        "fill": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Fill style as a CSS color string; omitted or empty for no fill"
        },
        "stroke": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Stroke style as a CSS color string; omitted or empty for no stroke"
        },
        "blockId": {
          "type": "string",
          "format": "at-uri",
          "description": "The AT-URI of this block record"
        },
        "opacity": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Opacity from 0 to 1 (defaults to 1)"
        },
        "rotation": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Rotation in radians around (cx, cy) (defaults to 0)"
        },
        "strokeWidth": {
          "ref": "page.corvus.core#register",
          "type": "ref",
          "description": "Stroke width in pixels (defaults to 1)"
        }
      },
      "description": "An ellipse or circle (set rx == ry for a circle)"
    },
    "pathCommand": {
      "type": "object",
      "required": [
        "op"
      ],
      "properties": {
        "op": {
          "type": "string",
          "description": "M=moveTo (x,y); L=lineTo (x,y); C=bezierCurveTo (cp1x,cp1y,cp2x,cp2y,x,y); Q=quadraticCurveTo (cpx,cpy,x,y); A=arc (cx,cy,r,startAngle,endAngle,counterclockwise); Z=closePath (no coords)",
          "knownValues": [
            "M",
            "L",
            "C",
            "Q",
            "A",
            "Z"
          ]
        },
        "coords": {
          "type": "array",
          "items": {
            "type": "integer"
          },
          "description": "Coordinate arguments; interpretation depends on op. Angles for the A command are encoded in milliradians (0 to 2π × 1000) so they fit an integer"
        }
      },
      "description": "A single path command. Used inline as a value in a #path.commands sequence — NOT its own block, NOT addressable, no stable identity across edits"
    },
    "strokePoint": {
      "type": "object",
      "required": [
        "x",
        "y"
      ],
      "properties": {
        "x": {
          "type": "integer",
          "description": "X coordinate in pixels"
        },
        "y": {
          "type": "integer",
          "description": "Y coordinate in pixels"
        },
        "pressure": {
          "type": "integer",
          "maximum": 255,
          "minimum": 0,
          "description": "Optional pen pressure, 0-255 (0 = lift, 255 = max)"
        }
      },
      "description": "A single sample within a #stroke. Used inline as an element of #stroke.points"
    }
  },
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1,
  "description": "A drawing block — a vector image composed of shapes that render onto an HTML canvas 2D context. The drawing's `shapes` sequence holds shape block ids in z-order (later = on top). Each shape variant below is its own block. Coordinates are integer pixels; an editor that needs sub-pixel precision can scale its working coord space."
}
```
