at.meme-museum.meme

meme-museum.at

Schema Diff

+85 -21

From

CID
bafyreiaph6v7us6...
Indexed At
2026-08-07 21:59 UTC
View this version

To

CID
bafyreieyedbzo5m...
Indexed At
2026-08-11 21:43 UTC
View this version

Compatibility Analysis

Breaking Changes Detected

13 breaking changes, 31 non-breaking changes.

Breaking Changes (13)
  • RequiredEdgeAdded RequiredEdgeAdded { vertex_id: "at.meme-museum.meme:body", src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.alt", kind: "prop", name: Some("alt") }
  • RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "at.meme-museum.meme:body", src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.name", kind: "prop", name: Some("name") }
  • RemovedVertex RemovedVertex { vertex_id: "app.bsky.richtext.facet" }
  • RemovedVertex RemovedVertex { vertex_id: "at.meme-museum.meme:body.avatar" }
  • RemovedVertex RemovedVertex { vertex_id: "at.meme-museum.meme:body.description" }
  • RemovedVertex RemovedVertex { vertex_id: "at.meme-museum.meme:body.descriptionFacets" }
  • RemovedVertex RemovedVertex { vertex_id: "at.meme-museum.meme:body.descriptionFacets:items" }
  • RemovedVertex RemovedVertex { vertex_id: "at.meme-museum.meme:body.name" }
  • RemovedEdge RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.avatar", kind: "prop", name: Some("avatar") }
  • RemovedEdge RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.description", kind: "prop", name: Some("description") }
  • RemovedEdge RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.descriptionFacets", kind: "prop", name: Some("descriptionFacets") }
  • RemovedEdge RemovedEdge { src: "at.meme-museum.meme:body.descriptionFacets", tgt: "at.meme-museum.meme:body.descriptionFacets:items", kind: "items", name: None }
  • RemovedEdge RemovedEdge { src: "at.meme-museum.meme:body.descriptionFacets:items", tgt: "app.bsky.richtext.facet", kind: "ref", name: None }
Non-Breaking Changes (31)
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme#source" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme#source.importedFrom" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme#source.note" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme#source.url" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.alt" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.duration" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.height" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.image" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.isAnimated" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.source" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.tags" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.tags:items" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.title" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.video" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.visibility" }
  • AddedVertex AddedVertex { vertex_id: "at.meme-museum.meme:body.width" }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.importedFrom", kind: "prop", name: Some("importedFrom") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.note", kind: "prop", name: Some("note") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.url", kind: "prop", name: Some("url") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.duration", kind: "prop", name: Some("duration") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.height", kind: "prop", name: Some("height") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.image", kind: "prop", name: Some("image") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.isAnimated", kind: "prop", name: Some("isAnimated") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.source", kind: "prop", name: Some("source") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.tags", kind: "prop", name: Some("tags") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.title", kind: "prop", name: Some("title") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.video", kind: "prop", name: Some("video") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.visibility", kind: "prop", name: Some("visibility") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.width", kind: "prop", name: Some("width") }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body.source", tgt: "at.meme-museum.meme#source", kind: "ref", name: None }
  • AddedEdge AddedEdge { src: "at.meme-museum.meme:body.tags", tgt: "at.meme-museum.meme:body.tags:items", kind: "items", name: None }

Migration Guidance

Removed Elements

  • RemovedVertex { vertex_id: "app.bsky.richtext.facet" }
  • RemovedVertex { vertex_id: "at.meme-museum.meme:body.avatar" }
  • RemovedVertex { vertex_id: "at.meme-museum.meme:body.description" }
  • RemovedVertex { vertex_id: "at.meme-museum.meme:body.descriptionFacets" }
  • RemovedVertex { vertex_id: "at.meme-museum.meme:body.descriptionFacets:items" }
  • RemovedVertex { vertex_id: "at.meme-museum.meme:body.name" }

Added Elements

  • AddedVertex { vertex_id: "at.meme-museum.meme#source" }
  • AddedVertex { vertex_id: "at.meme-museum.meme#source.importedFrom" }
  • AddedVertex { vertex_id: "at.meme-museum.meme#source.note" }
  • AddedVertex { vertex_id: "at.meme-museum.meme#source.url" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.alt" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.duration" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.height" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.image" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.isAnimated" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.source" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.tags" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.tags:items" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.title" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.video" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.visibility" }
  • AddedVertex { vertex_id: "at.meme-museum.meme:body.width" }

Additional Notes

  • Breaking: RequiredEdgeAdded { vertex_id: "at.meme-museum.meme:body", src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.alt", kind: "prop", name: Some("alt") }
  • Breaking: RequiredEdgeRemoved { vertex_id: "at.meme-museum.meme:body", src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.name", kind: "prop", name: Some("name") }
  • Breaking: RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.avatar", kind: "prop", name: Some("avatar") }
  • Breaking: RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.description", kind: "prop", name: Some("description") }
  • Breaking: RemovedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.descriptionFacets", kind: "prop", name: Some("descriptionFacets") }
  • Breaking: RemovedEdge { src: "at.meme-museum.meme:body.descriptionFacets", tgt: "at.meme-museum.meme:body.descriptionFacets:items", kind: "items", name: None }
  • Breaking: RemovedEdge { src: "at.meme-museum.meme:body.descriptionFacets:items", tgt: "app.bsky.richtext.facet", kind: "ref", name: None }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.importedFrom", kind: "prop", name: Some("importedFrom") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.note", kind: "prop", name: Some("note") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme#source", tgt: "at.meme-museum.meme#source.url", kind: "prop", name: Some("url") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.duration", kind: "prop", name: Some("duration") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.height", kind: "prop", name: Some("height") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.image", kind: "prop", name: Some("image") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.isAnimated", kind: "prop", name: Some("isAnimated") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.source", kind: "prop", name: Some("source") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.tags", kind: "prop", name: Some("tags") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.title", kind: "prop", name: Some("title") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.video", kind: "prop", name: Some("video") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.visibility", kind: "prop", name: Some("visibility") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body", tgt: "at.meme-museum.meme:body.width", kind: "prop", name: Some("width") }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body.source", tgt: "at.meme-museum.meme#source", kind: "ref", name: None }
  • Non-breaking: AddedEdge { src: "at.meme-museum.meme:body.tags", tgt: "at.meme-museum.meme:body.tags:items", kind: "items", name: None }
1 1
{
2 2
  "id": "at.meme-museum.meme",
3 3
  "defs": {
4 4
    "main": {
5 -
      "key": "any",
5 +
      "key": "tid",
6 6
      "type": "record",
7 7
      "record": {
8 8
        "type": "object",
9 9
        "required": [
10 -
          "name",
10 +
          "alt",
11 11
          "createdAt"
12 12
        ],
13 13
        "properties": {
14 -
          "name": {
14 +
          "alt": {
15 15
            "type": "string",
16 -
            "maxLength": 640,
17 -
            "minLength": 1,
18 -
            "description": "TODO: title name of record; can not be empty",
19 -
            "maxGraphemes": 64
16 +
            "maxLength": 2000,
17 +
            "description": "Accessibility alt text. Required, same convention as app.bsky.embed.images.",
18 +
            "maxGraphemes": 1000
20 19
          },
21 -
          "avatar": {
20 +
          "tags": {
21 +
            "type": "array",
22 +
            "items": {
23 +
              "type": "string",
24 +
              "maxLength": 64
25 +
            },
26 +
            "maxLength": 25
27 +
          },
28 +
          "image": {
22 29
            "type": "blob",
23 30
            "accept": [
24 31
              "image/png",
25 -
              "image/jpeg"
32 +
              "image/jpeg",
33 +
              "image/webp",
34 +
              "image/gif"
26 35
            ],
27 -
            "maxSize": 2000000
36 +
            "maxSize": 8000000,
37 +
            "description": "The asset, when this meme is an image. Exactly one of image/video is set -- a constraint Lexicon can't express, so it's enforced client-side. Neither is required here so that adding video didn't have to break records written before it existed."
38 +
          },
39 +
          "title": {
40 +
            "type": "string",
41 +
            "maxLength": 300,
42 +
            "description": "Short human label for the meme, distinct from alt text (e.g. \"distracted boyfriend\").",
43 +
            "maxGraphemes": 100
44 +
          },
45 +
          "video": {
46 +
            "type": "blob",
47 +
            "accept": [
48 +
              "video/mp4"
49 +
            ],
50 +
            "maxSize": 100000000,
51 +
            "description": "The asset, when this meme is a video clip. Always mp4 regardless of what the user picked: the blob is the one Bluesky's video service transcodes and writes back to the PDS, and app.bsky.embed.video accepts nothing else."
52 +
          },
53 +
          "width": {
54 +
            "type": "integer",
55 +
            "minimum": 1
56 +
          },
57 +
          "height": {
58 +
            "type": "integer",
59 +
            "minimum": 1
60 +
          },
61 +
          "source": {
62 +
            "ref": "#source",
63 +
            "type": "ref"
64 +
          },
65 +
          "duration": {
66 +
            "type": "integer",
67 +
            "minimum": 1,
68 +
            "description": "Video memes only: clip length in milliseconds, read client-side at upload time. Omitted when the browser couldn't decode metadata for the picked file."
28 69
          },
29 70
          "createdAt": {
30 71
            "type": "string",
31 72
            "format": "datetime"
32 73
          },
33 -
          "description": {
34 -
            "type": "string",
35 -
            "maxLength": 3000,
36 -
            "maxGraphemes": 300
74 +
          "isAnimated": {
75 +
            "type": "boolean",
76 +
            "description": "Image memes only: set client-side from frame-count inspection at upload time, since it isn't reliably inferable from mimetype alone. Not written for video, where it would be trivially true."
37 77
          },
38 -
          "descriptionFacets": {
39 -
            "type": "array",
40 -
            "items": {
41 -
              "ref": "app.bsky.richtext.facet",
42 -
              "type": "ref"
43 -
            }
78 +
          "visibility": {
79 +
            "type": "string",
80 +
            "default": "public",
81 +
            "maxLength": 64,
82 +
            "description": "Soft signal only, not access control -- see docs/data-model.md.",
83 +
            "knownValues": [
84 +
              "public",
85 +
              "unlisted"
86 +
            ]
44 87
          }
45 88
        }
46 89
      },
47 -
      "description": "TODO: describe purpose of this schema"
90 +
      "description": "A single meme asset (still image, animated image, or short video clip) in a user's library."
91 +
    },
92 +
    "source": {
93 +
      "type": "object",
94 +
      "properties": {
95 +
        "url": {
96 +
          "type": "string",
97 +
          "format": "uri",
98 +
          "description": "A webpage the image came from, if relevant."
99 +
        },
100 +
        "note": {
101 +
          "type": "string",
102 +
          "maxLength": 500,
103 +
          "description": "Free-text credit, e.g. \"via @someone.bsky.social\"."
104 +
        },
105 +
        "importedFrom": {
106 +
          "type": "string",
107 +
          "format": "at-uri",
108 +
          "description": "If copied in from another ATProto app's or user's collection, the original record's at-uri."
109 +
        }
110 +
      },
111 +
      "description": "Provenance/attribution for a meme, if known."
48 112
    }
49 113
  },
50 114
  "$type": "com.atproto.lexicon.schema",
51 115
  "lexicon": 1
52 116
}

Compare Other Versions

Lexicon Garden

@