pics.2bit.feed.photo

2bit.pics

Schema Diff

+22 -7

From

CID
bafyreihme3zpe33...
Indexed At
2026-08-20 03:52 UTC
View this version

To

CID
bafyreibruv4zskl...
Indexed At
2026-08-25 04:28 UTC
View this version

Compatibility Analysis

Breaking Changes Detected

2 breaking changes, 16 non-breaking changes.

Breaking Changes (2)
  • RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "pics.2bit.feed.photo:body", src: "pics.2bit.feed.photo:body", tgt: "pics.2bit.feed.photo:body.colors", kind: "prop", name: Some("colors") }
  • RequiredEdgeRemoved RequiredEdgeRemoved { vertex_id: "pics.2bit.feed.photo:body", src: "pics.2bit.feed.photo:body", tgt: "pics.2bit.feed.photo:body.image", kind: "prop", name: Some("image") }
Non-Breaking Changes (16)
  • AddedVertex AddedVertex { vertex_id: "app.bsky.richtext.facet" }
  • AddedVertex AddedVertex { vertex_id: "pics.2bit.feed.photo:body.content" }
  • AddedVertex AddedVertex { vertex_id: "pics.2bit.feed.photo:body.content:variant0" }
  • AddedVertex AddedVertex { vertex_id: "pics.2bit.feed.photo:body.content:variant1" }
  • AddedVertex AddedVertex { vertex_id: "pics.2bit.feed.photo:body.facets" }
  • AddedVertex AddedVertex { vertex_id: "pics.2bit.feed.photo:body.facets:items" }
  • AddedVertex AddedVertex { vertex_id: "pics.2bit.image#mono" }
  • AddedVertex AddedVertex { vertex_id: "pics.2bit.image#trichrome" }
  • AddedEdge AddedEdge { src: "pics.2bit.feed.photo:body", tgt: "pics.2bit.feed.photo:body.content", kind: "prop", name: Some("content") }
  • AddedEdge AddedEdge { src: "pics.2bit.feed.photo:body", tgt: "pics.2bit.feed.photo:body.facets", kind: "prop", name: Some("facets") }
  • AddedEdge AddedEdge { src: "pics.2bit.feed.photo:body.content", tgt: "pics.2bit.feed.photo:body.content:variant0", kind: "variant", name: Some("pics.2bit.image#mono") }
  • AddedEdge AddedEdge { src: "pics.2bit.feed.photo:body.content", tgt: "pics.2bit.feed.photo:body.content:variant1", kind: "variant", name: Some("pics.2bit.image#trichrome") }
  • AddedEdge AddedEdge { src: "pics.2bit.feed.photo:body.content:variant0", tgt: "pics.2bit.image#mono", kind: "ref", name: None }
  • AddedEdge AddedEdge { src: "pics.2bit.feed.photo:body.content:variant1", tgt: "pics.2bit.image#trichrome", kind: "ref", name: None }
  • AddedEdge AddedEdge { src: "pics.2bit.feed.photo:body.facets", tgt: "pics.2bit.feed.photo:body.facets:items", kind: "items", name: None }
  • AddedEdge AddedEdge { src: "pics.2bit.feed.photo:body.facets:items", tgt: "app.bsky.richtext.facet", kind: "ref", name: None }

Migration Guidance

Added Elements

  • AddedVertex { vertex_id: "app.bsky.richtext.facet" }
  • AddedVertex { vertex_id: "pics.2bit.feed.photo:body.content" }
  • AddedVertex { vertex_id: "pics.2bit.feed.photo:body.content:variant0" }
  • AddedVertex { vertex_id: "pics.2bit.feed.photo:body.content:variant1" }
  • AddedVertex { vertex_id: "pics.2bit.feed.photo:body.facets" }
  • AddedVertex { vertex_id: "pics.2bit.feed.photo:body.facets:items" }
  • AddedVertex { vertex_id: "pics.2bit.image#mono" }
  • AddedVertex { vertex_id: "pics.2bit.image#trichrome" }

Additional Notes

  • Breaking: RequiredEdgeRemoved { vertex_id: "pics.2bit.feed.photo:body", src: "pics.2bit.feed.photo:body", tgt: "pics.2bit.feed.photo:body.colors", kind: "prop", name: Some("colors") }
  • Breaking: RequiredEdgeRemoved { vertex_id: "pics.2bit.feed.photo:body", src: "pics.2bit.feed.photo:body", tgt: "pics.2bit.feed.photo:body.image", kind: "prop", name: Some("image") }
  • Non-breaking: AddedEdge { src: "pics.2bit.feed.photo:body", tgt: "pics.2bit.feed.photo:body.content", kind: "prop", name: Some("content") }
  • Non-breaking: AddedEdge { src: "pics.2bit.feed.photo:body", tgt: "pics.2bit.feed.photo:body.facets", kind: "prop", name: Some("facets") }
  • Non-breaking: AddedEdge { src: "pics.2bit.feed.photo:body.content", tgt: "pics.2bit.feed.photo:body.content:variant0", kind: "variant", name: Some("pics.2bit.image#mono") }
  • Non-breaking: AddedEdge { src: "pics.2bit.feed.photo:body.content", tgt: "pics.2bit.feed.photo:body.content:variant1", kind: "variant", name: Some("pics.2bit.image#trichrome") }
  • Non-breaking: AddedEdge { src: "pics.2bit.feed.photo:body.content:variant0", tgt: "pics.2bit.image#mono", kind: "ref", name: None }
  • Non-breaking: AddedEdge { src: "pics.2bit.feed.photo:body.content:variant1", tgt: "pics.2bit.image#trichrome", kind: "ref", name: None }
  • Non-breaking: AddedEdge { src: "pics.2bit.feed.photo:body.facets", tgt: "pics.2bit.feed.photo:body.facets:items", kind: "items", name: None }
  • Non-breaking: AddedEdge { src: "pics.2bit.feed.photo:body.facets:items", tgt: "app.bsky.richtext.facet", kind: "ref", name: None }
1 1
{
2 2
  "id": "pics.2bit.feed.photo",
3 3
  "defs": {
4 4
    "main": {
5 5
      "key": "tid",
6 6
      "type": "record",
7 7
      "record": {
8 8
        "type": "object",
9 9
        "required": [
10 -
          "image",
11 -
          "colors",
12 10
          "createdAt"
13 11
        ],
14 12
        "properties": {
15 13
          "alt": {
16 14
            "type": "string",
17 15
            "maxLength": 3000,
18 16
            "description": "Alt text for accessibility.",
19 17
            "maxGraphemes": 300
20 18
          },
21 19
          "image": {
22 20
            "type": "bytes",
23 21
            "maxLength": 3584,
24 22
            "minLength": 3584,
25 -
            "description": "128x112 2bpp Game Boy Camera tile data: 16x14 tiles in row-major order, 16 bytes per tile (8 rows of low+high bit-plane bytes, MSB-first)."
23 +
            "description": "Superseded by `content`, and written only by records that predate it: 128x112 2bpp Game Boy Camera tile data, 16x14 tiles in row-major order, 16 bytes per tile (8 rows of low+high bit-plane bytes, MSB-first). Read together with `colors` it means exactly what a one-exposure pics.2bit.image#mono means, and this app reads it as one. Kept declared rather than deleted because HappyView extracts a record through its lexicon and keeps only the properties the schema names - dropping this would index every old photo with its pixels silently removed."
26 24
          },
27 25
          "colors": {
28 26
            "type": "array",
29 27
            "items": {
30 28
              "type": "integer",
31 29
              "maximum": 16777215,
32 30
              "minimum": 0
33 31
            },
34 32
            "maxLength": 4,
35 33
            "minLength": 4,
36 -
            "description": "Four 24-bit RGB colors (0 to 0xFFFFFF) corresponding to 2bpp pixel values 0 through 3, where 0 is lightest and 3 is darkest."
34 +
            "description": "Superseded by pics.2bit.image#mono `colors`, and written only alongside `image`. Four 24-bit RGB colors (0 to 0xFFFFFF) corresponding to 2bpp pixel values 0 through 3, where 0 is lightest and 3 is darkest."
35 +
          },
36 +
          "facets": {
37 +
            "type": "array",
38 +
            "items": {
39 +
              "ref": "app.bsky.richtext.facet",
40 +
              "type": "ref"
41 +
            },
42 +
            "maxLength": 64,
43 +
            "description": "Annotations of `caption`, in the shape Bluesky uses for rich text - hashtags and mentions today, and whatever this app grows next. Byte offsets index the UTF-8 encoding of `caption`, not its characters. Written by the author's client rather than derived here: what a facet records is what the author meant by a run of their own text, which is theirs to say. This app's AppView refuses any facet whose range falls outside the caption, whose tag doesn't match the text it covers, or whose mention doesn't cover a handle - so an indexed tag or mention always corresponds to something actually written."
37 44
          },
38 45
          "labels": {
39 46
            "ref": "com.atproto.label.defs#selfLabels",
40 47
            "type": "ref",
41 -
            "description": "Self-applied content labels, set by the author. 2bit.pics writes at most one of porn/sexual/nudity/graphic-media; clients blur or warn on labeled photos."
48 +
            "description": "Self-applied content labels, set by the author. 2bit.pics writes any of porn/sexual/nudity/graphic-media, at most one of which is porn/sexual/nudity; clients blur or warn on labeled photos."
42 49
          },
43 50
          "caption": {
44 51
            "type": "string",
45 52
            "maxLength": 5000,
46 -
            "description": "Free-text caption.",
53 +
            "description": "Free-text caption. Any #hashtags in it are read out by this app's AppView and indexed there; nothing about them is stored on the record.",
47 54
            "maxGraphemes": 500
48 55
          },
56 +
          "content": {
57 +
            "refs": [
58 +
              "pics.2bit.image#mono",
59 +
              "pics.2bit.image#trichrome"
60 +
            ],
61 +
            "type": "union",
62 +
            "description": "The photo's pixels. Exactly one shape, so a photo is never two kinds at once. Optional only while records predating this field remain unmigrated - every record written from now on carries it. Readers should skip a $type they don't recognize rather than render it broken, so new kinds can be added without breaking older clients; this union must never be closed, for the same reason."
63 +
          },
49 64
          "createdAt": {
50 65
            "type": "string",
51 66
            "format": "datetime",
52 67
            "description": "When this photo record was published."
53 68
          }
54 69
        }
55 70
      },
56 -
      "description": "A single 4-shade, low-resolution photo. The core record of 2bit.pics."
71 +
      "description": "A single low-resolution photo. The core record of 2bit.pics. Its pixels live in `content`: a four-shade mono photo or a color trichrome, either one a stack of one or more 2bpp exposures whose planes sit in a blob rather than on the record. `image` and `colors` are what records written before `content` existed carry instead; a record carrying neither `content` nor `image` is not a photo, and this app's AppView refuses to write one and skips one arriving from the network rather than indexing a photo with nothing in it."
57 72
    }
58 73
  },
59 74
  "$type": "com.atproto.lexicon.schema",
60 75
  "lexicon": 1
61 76
}

Compare Other Versions

Lexicon Garden

@