{
  "lexicon": 1,
  "id": "space.polymodel.library.defs",
  "defs": {
    "actor": {
      "type": "object",
      "required": [
        "did",
        "handle"
      ],
      "properties": {
        "did": {
          "type": "string",
          "format": "did"
        },
        "handle": {
          "type": "string",
          "format": "handle"
        },
        "displayName": {
          "type": "string"
        },
        "avatar": {
          "type": "string",
          "format": "uri",
          "description": "Avatar image URL resolved by the app view (CDN)."
        },
        "pronouns": {
          "type": "string",
          "description": "Hydrated profile pronouns for bylines and cards."
        },
        "description": {
          "type": "string"
        },
        "followerCount": {
          "type": "integer"
        },
        "followingCount": {
          "type": "integer"
        },
        "thingCount": {
          "type": "integer",
          "description": "Count of published Polymodel things by this actor."
        },
        "viewer": {
          "type": "ref",
          "ref": "#actorViewerState"
        }
      }
    },
    "viewerState": {
      "type": "object",
      "properties": {
        "like": {
          "type": "string",
          "format": "at-uri"
        },
        "save": {
          "type": "string",
          "format": "at-uri"
        }
      }
    },
    "bbox": {
      "type": "object",
      "description": "Axis-aligned bounding-box dimensions. ATProto has no float type, so x/y/z are decimal strings (e.g. 12.5) parsed to floats internally.",
      "properties": {
        "x": {
          "type": "string"
        },
        "y": {
          "type": "string"
        },
        "z": {
          "type": "string"
        },
        "unit": {
          "type": "string"
        }
      },
      "required": [
        "x",
        "y",
        "z"
      ]
    },
    "aspectRatio": {
      "type": "object",
      "description": "Width:height aspect ratio of an image, for layout before the blob loads.",
      "required": [
        "width",
        "height"
      ],
      "properties": {
        "width": {
          "type": "integer"
        },
        "height": {
          "type": "integer"
        }
      }
    },
    "image": {
      "type": "object",
      "description": "An authored image: a blob plus alt text and aspect ratio. Stored on records; the app view resolves it to #imageView.",
      "required": [
        "image",
        "alt",
        "aspectRatio"
      ],
      "properties": {
        "image": {
          "type": "blob",
          "accept": [
            "image/png",
            "image/jpeg",
            "image/webp"
          ],
          "maxSize": 5242880
        },
        "alt": {
          "type": "string",
          "maxGraphemes": 300,
          "maxLength": 2000,
          "description": "Alt text describing the image, for accessibility."
        },
        "aspectRatio": {
          "type": "ref",
          "ref": "#aspectRatio"
        }
      }
    },
    "imageView": {
      "type": "object",
      "description": "A resolved image view: CDN URLs for thumbnail and full size plus aspect ratio. Currently resolved via Bluesky's CDN by the app view.",
      "required": [
        "thumb",
        "fullsize"
      ],
      "properties": {
        "alt": {
          "type": "string"
        },
        "thumb": {
          "type": "string",
          "format": "uri",
          "description": "Fully-qualified thumbnail URL (CDN, resolved by the app view)."
        },
        "fullsize": {
          "type": "string",
          "format": "uri",
          "description": "Fully-qualified full-size URL (CDN, resolved by the app view)."
        },
        "aspectRatio": {
          "type": "ref",
          "ref": "#aspectRatio"
        }
      }
    },
    "file": {
      "type": "object",
      "description": "Chunk-capable geometry manifest. Reassemble by concatenating chunks in offset order. Per-chunk integrity is the blob CID; offset+size make ordering explicit; digest verifies the fully reassembled file.",
      "properties": {
        "mimeType": {
          "type": "string"
        },
        "size": {
          "type": "integer"
        },
        "digest": {
          "type": "string",
          "description": "hex digest of the fully reassembled file (sha256 by convention)"
        },
        "chunks": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#chunk"
          },
          "maxLength": 4096
        }
      },
      "required": [
        "mimeType",
        "size",
        "chunks"
      ]
    },
    "chunk": {
      "type": "object",
      "properties": {
        "blob": {
          "type": "blob",
          "accept": [
            "model/stl",
            "model/3mf",
            "model/obj",
            "application/octet-stream"
          ],
          "maxSize": 104857600
        },
        "offset": {
          "type": "integer",
          "minimum": 0
        },
        "size": {
          "type": "integer",
          "minimum": 0
        }
      },
      "required": [
        "blob",
        "offset",
        "size"
      ]
    },
    "thingView": {
      "type": "object",
      "required": [
        "uri",
        "cid",
        "author",
        "record",
        "indexedAt",
        "name",
        "license",
        "likeCount",
        "saveCount",
        "modelCount",
        "partCount",
        "viewer"
      ],
      "properties": {
        "uri": {
          "type": "string",
          "format": "at-uri"
        },
        "cid": {
          "type": "string"
        },
        "author": {
          "type": "ref",
          "ref": "#actor"
        },
        "record": {
          "type": "unknown"
        },
        "indexedAt": {
          "type": "string",
          "format": "datetime"
        },
        "name": {
          "type": "string"
        },
        "summary": {
          "type": "string"
        },
        "license": {
          "type": "string"
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Hydrated display tags, including appview-aggregated external tag assertions."
        },
        "cover": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#imageView"
          }
        },
        "previews": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#imageView"
          }
        },
        "derivedFrom": {
          "type": "ref",
          "ref": "com.atproto.repo.strongRef"
        },
        "intendedToWorkWith": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "com.atproto.repo.strongRef"
          }
        },
        "likeCount": {
          "type": "integer"
        },
        "saveCount": {
          "type": "integer"
        },
        "modelCount": {
          "type": "integer"
        },
        "partCount": {
          "type": "integer",
          "description": "Thing-level aggregate count of parts across included models, computed by the app view."
        },
        "viewer": {
          "type": "ref",
          "ref": "#viewerState"
        }
      }
    },
    "thingViewBasic": {
      "type": "object",
      "required": [
        "uri",
        "cid",
        "author",
        "name",
        "likeCount",
        "saveCount",
        "modelCount",
        "partCount",
        "indexedAt",
        "viewer"
      ],
      "properties": {
        "uri": {
          "type": "string",
          "format": "at-uri"
        },
        "cid": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "author": {
          "type": "ref",
          "ref": "#actor"
        },
        "cover": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#imageView"
          }
        },
        "previews": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#imageView"
          }
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Hydrated display tags for browse/search/profile cards, including appview-aggregated external tag assertions."
        },
        "likeCount": {
          "type": "integer"
        },
        "saveCount": {
          "type": "integer"
        },
        "modelCount": {
          "type": "integer"
        },
        "partCount": {
          "type": "integer",
          "description": "Thing-level aggregate count of parts across included models, computed by the app view."
        },
        "indexedAt": {
          "type": "string",
          "format": "datetime"
        },
        "viewer": {
          "type": "ref",
          "ref": "#viewerState"
        }
      }
    },
    "modelView": {
      "type": "object",
      "required": [
        "uri",
        "cid",
        "author",
        "record",
        "indexedAt",
        "name",
        "partCount",
        "viewer"
      ],
      "properties": {
        "uri": {
          "type": "string",
          "format": "at-uri"
        },
        "cid": {
          "type": "string"
        },
        "author": {
          "type": "ref",
          "ref": "#actor"
        },
        "record": {
          "type": "unknown"
        },
        "indexedAt": {
          "type": "string",
          "format": "datetime"
        },
        "name": {
          "type": "string"
        },
        "summary": {
          "type": "string"
        },
        "cover": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#imageView"
          }
        },
        "previews": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#imageView"
          }
        },
        "partCount": {
          "type": "integer"
        },
        "viewer": {
          "type": "ref",
          "ref": "#viewerState"
        }
      }
    },
    "partView": {
      "type": "object",
      "required": [
        "uri",
        "cid",
        "author",
        "record",
        "indexedAt",
        "name",
        "file",
        "viewer"
      ],
      "properties": {
        "uri": {
          "type": "string",
          "format": "at-uri"
        },
        "cid": {
          "type": "string"
        },
        "author": {
          "type": "ref",
          "ref": "#actor"
        },
        "record": {
          "type": "unknown"
        },
        "indexedAt": {
          "type": "string",
          "format": "datetime"
        },
        "name": {
          "type": "string"
        },
        "format": {
          "type": "string"
        },
        "file": {
          "type": "ref",
          "ref": "#file"
        },
        "previews": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#imageView"
          }
        },
        "viewer": {
          "type": "ref",
          "ref": "#viewerState"
        }
      }
    },
    "feedItem": {
      "type": "object",
      "properties": {
        "thing": {
          "type": "ref",
          "ref": "#thingViewBasic"
        }
      },
      "required": [
        "thing"
      ]
    },
    "feedView": {
      "type": "object",
      "properties": {
        "cursor": {
          "type": "string"
        },
        "items": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#feedItem"
          }
        }
      },
      "required": [
        "items"
      ]
    },
    "actorViewDetailed": {
      "type": "object",
      "description": "Detailed hydrated actor/profile view for profile surfaces, modeled after app.bsky.actor profile view splits.",
      "required": [
        "did",
        "handle",
        "record",
        "indexedAt",
        "viewer"
      ],
      "properties": {
        "did": {
          "type": "string",
          "format": "did"
        },
        "handle": {
          "type": "string",
          "format": "handle"
        },
        "displayName": {
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "avatar": {
          "type": "string",
          "format": "uri",
          "description": "Avatar image URL resolved by the app view (CDN)."
        },
        "pronouns": {
          "type": "string"
        },
        "defaultLicense": {
          "type": "string"
        },
        "printers": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "links": {
          "type": "array",
          "items": {
            "type": "string",
            "format": "uri"
          }
        },
        "followerCount": {
          "type": "integer"
        },
        "followingCount": {
          "type": "integer"
        },
        "thingCount": {
          "type": "integer",
          "description": "Count of published Polymodel things by this actor."
        },
        "record": {
          "type": "unknown"
        },
        "indexedAt": {
          "type": "string",
          "format": "datetime"
        },
        "viewer": {
          "type": "ref",
          "ref": "#actorViewerState"
        }
      }
    },
    "workMeta": {
      "type": "object",
      "description": "Reference-only shared field set; fields are inlined on thing/model.",
      "properties": {
        "name": {
          "type": "string"
        },
        "summary": {
          "type": "string"
        },
        "instructions": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "license": {
          "type": "string"
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "cover": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#image"
          }
        },
        "previews": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "#image"
          }
        },
        "derivedFrom": {
          "type": "ref",
          "ref": "com.atproto.repo.strongRef"
        },
        "intendedToWorkWith": {
          "type": "array",
          "items": {
            "type": "ref",
            "ref": "com.atproto.repo.strongRef"
          }
        }
      }
    },
    "actorViewerState": {
      "type": "object",
      "description": "Viewer-specific relationship state for an actor/profile.",
      "properties": {
        "following": {
          "type": "string",
          "format": "at-uri",
          "description": "Follow record URI if the requester follows this actor."
        },
        "followedBy": {
          "type": "string",
          "format": "at-uri",
          "description": "Follow record URI if this actor follows the requester."
        },
        "muted": {
          "type": "boolean"
        },
        "blockedBy": {
          "type": "boolean"
        },
        "blocking": {
          "type": "string",
          "format": "at-uri",
          "description": "Block record URI if the requester blocks this actor."
        }
      }
    }
  }
}
