{
  "path": "/3m56tzfj5pc2a",
  "site": "at://did:plc:s2rczyxit2v5vzedxqs326ri/site.standard.publication/3m2jpv5avx22n",
  "tags": [
    "ATproto",
    "CMS",
    "Standard Site",
    "Atmosphere",
    "Blogging",
    "Publishing",
    "Lexicons"
  ],
  "$type": "site.standard.document",
  "title": "Integrating your Atmosphere account content in your web projects",
  "content": {
    "$type": "pub.leaflet.content",
    "pages": [
      {
        "id": "019a679b-ba8d-722b-9dad-74834f9b4a00",
        "$type": "pub.leaflet.pages.linearDocument",
        "blocks": [
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.image",
              "image": {
                "$type": "blob",
                "ref": {
                  "$link": "bafkreiacfnw7d4xyrye3ey36qpzahprnqi6fdbrsfee6ypc7vdfe5zaxn4"
                },
                "mimeType": "image/png",
                "size": 989225
              },
              "fullBleed": true,
              "aspectRatio": {
                "width": 1194,
                "height": 669
              }
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 15,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 24,
                    "byteStart": 19
                  },
                  "features": [
                    {
                      "uri": "https://www.deviantart.com/lofipromt",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "Skyscape Towers by Lofip"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.blockquote",
              "facets": [
                {
                  "index": {
                    "byteEnd": 19,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    },
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 116,
                    "byteStart": 19
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "Updated April 2026: I rebuilt the site from the bottom up, and so I have replaced the links and images in this post."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.horizontalRule"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 51,
                    "byteStart": 39
                  },
                  "features": [
                    {
                      "uri": "http://renderg.host",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 135,
                    "byteStart": 128
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "I'm rebuilding my own personal site at renderg.host as a learning project—a simple React site where I can control everything, without depending on increasingly expensive locked-in platforms."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "I was a happy Webflow+Wordpress user for a while. As someone still learning web dev, the builder UX is genuinely great, but their pricing? Not so much."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 53,
                    "byteStart": 48
                  },
                  "features": [
                    {
                      "uri": "https://ghost.org/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 64,
                    "byteStart": 58
                  },
                  "features": [
                    {
                      "uri": "https://strapi.io/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 144,
                    "byteStart": 137
                  },
                  "features": [
                    {
                      "uri": "https://leaflet.pub",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 176,
                    "byteStart": 146
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 205,
                    "byteStart": 197
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 227,
                    "byteStart": 216
                  },
                  "features": [
                    {
                      "uri": "https://atproto.com/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 319,
                    "byteStart": 311
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "This week, as I considered my CMS options (like Ghost and Strapi), I had an epiphany: I'm already publishing to multiple publications on Leaflet. Why waste time replicating it? Why not connect all my stuff together? AT Protocol provides everything I need—for free—and I retain full ownership and control of my stuff."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 85,
                    "byteStart": 77
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 99,
                    "byteStart": 96
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 108,
                    "byteStart": 99
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    },
                    {
                      "uri": "https://atproto.com/guides/glossary#data-repo",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 135,
                    "byteStart": 128
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#strikethrough"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 149,
                    "byteStart": 146
                  },
                  "features": [
                    {
                      "uri": "https://atproto.com/guides/glossary#pds-personal-data-server",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 234,
                    "byteStart": 214
                  },
                  "features": [
                    {
                      "uri": "https://underreacted.leaflet.pub/3m23gqakbqs2j",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 284,
                    "byteStart": 278
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "No vendor lock-in, no proprietary formats, no surprise pricing changes, just my stuff living in my data repo (hosted for now on Bluesky Eurosky's PDS). So rather than worry about if I could or should, I remembered I can just do things and gave it a shot! It's going really well so far."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 1,
              "plaintext": "I made this"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 119,
                    "byteStart": 113
                  },
                  "features": [
                    {
                      "uri": "https://pdsls.dev/at://did:plc:s2rczyxit2v5vzedxqs326ri",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "When readers visit the articles page on my site, they'll see content fetched in real-time from records stored in my PDS."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 31,
                    "byteStart": 24
                  },
                  "features": [
                    {
                      "uri": "https://leaflet.pub/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 197,
                    "byteStart": 185
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    },
                    {
                      "uri": "https://www.freecodecamp.org/news/what-is-headless-cms-explained/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "I can write articles on Leaflet, and they automatically appear on my site. Leaflet is essentially my CMS, even though it wasn't designed to do this and has no features specifically for headlessness."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.image",
              "image": {
                "$type": "blob",
                "ref": {
                  "$link": "bafkreiaivbkzt5ppxjfahmc6qhrzpjp445bp3ejlf2qar4um3i3req27ii"
                },
                "mimeType": "image/webp",
                "size": 353682
              },
              "fullBleed": true,
              "aspectRatio": {
                "width": 1920,
                "height": 1080
              }
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 20,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "uri": "https://renderg.host/writing",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "renderg.host/writing"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "alt": "A screenshot of my Leaflet publication called \"Annotations\" with a selection of posts.",
              "$type": "pub.leaflet.blocks.image",
              "image": {
                "$type": "blob",
                "ref": {
                  "$link": "bafkreiaujpvesjrmj6qmcvtzspymy2sxtgkk5gnsuywsgxx3tagpzk4ts4"
                },
                "mimeType": "image/webp",
                "size": 84332
              },
              "fullBleed": true,
              "aspectRatio": {
                "width": 1920,
                "height": 1080
              }
            },
            "alignment": "lex:pub.leaflet.pages.linearDocument#textAlignJustify"
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 23,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "uri": "https://renderghost.leaflet.pub/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "renderghost.leaflet.pub"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "alt": "A screenshot of my Leaflet publication called \"Marginalia\" with a selection of posts.",
              "$type": "pub.leaflet.blocks.image",
              "image": {
                "$type": "blob",
                "ref": {
                  "$link": "bafkreidpgy6qsd4fh7errgxrnqaz7pubs252wu4sg3s7nddsou77ximyxu"
                },
                "mimeType": "image/webp",
                "size": 113540
              },
              "fullBleed": true,
              "aspectRatio": {
                "width": 1920,
                "height": 1080
              }
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 22,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "uri": "https://marginalia.leaflet.pub/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "marginalia.leaflet.pub"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 133,
                    "byteStart": 36
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "It's surprisingly straightforward—no complicated backend, no database, no API keys, just simple HTTP requests to public endpoints. Because everything lives in my data repo, I could switch to any other AT Proto compatible hosting tomorrow and nothing (or so they tell me) would break 🤞."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.blockquote",
              "facets": [
                {
                  "index": {
                    "byteEnd": 18,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 57,
                    "byteStart": 50
                  },
                  "features": [
                    {
                      "uri": "https://eurosky.tech/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 69,
                    "byteStart": 62
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "Update April 2026: I recently switched hosting to Eurosky and nothing broke when I make this single change to my site's code."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.bskyPost",
              "postRef": {
                "cid": "bafyreidzmp6yryadx4bz5htl3oicgq47if5lhcq43adzolxesdhe2gs7me",
                "uri": "at://did:plc:s2rczyxit2v5vzedxqs326ri/app.bsky.feed.post/3mip5k656qk2l"
              },
              "clientHost": "bsky.app"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 1,
              "plaintext": "Initial Setup"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 21,
                    "byteStart": 17
                  },
                  "features": [
                    {
                      "uri": "https://atproto.com/guides/glossary#xrpc",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "AT Protocol uses XRPC to let you query data from any PDS. You don't need authentication for public data—just construct the right URL and fetch away."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 23,
                    "byteStart": 20
                  },
                  "features": [
                    {
                      "uri": "https://atproto.com/guides/glossary#did-decentralized-id",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 53,
                    "byteStart": 50
                  },
                  "features": [
                    {
                      "uri": "https://atproto.com/guides/glossary#pds-personal-data-server",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 83,
                    "byteStart": 72
                  },
                  "features": [
                    {
                      "uri": "https://atproto.com/guides/glossary#collection",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "First, I declare my DID (personal identifier) and PDS location, and the collections I want to reference."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "typescript",
              "plaintext": "export const ATPROTO_CONFIG = {\n  DID: 'did:plc:s2rczyxit2v5vzedxqs326ri',\n  PDS_URL: 'https://rooter.us-west.host.bsky.network',\n  CDN_URL: 'https://cdn.bsky.app',\n} as const;\n\nexport const ATPROTO_COLLECTIONS = {\n  PUBLICATION: 'pub.leaflet.publication',\n  DOCUMENT: 'pub.leaflet.document',\n} as const;\n",
              "syntaxHighlightingTheme": "github-dark-default"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.blockquote",
              "facets": [
                {
                  "index": {
                    "byteEnd": 18,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    },
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 43,
                    "byteStart": 18
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 56,
                    "byteStart": 43
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    },
                    {
                      "uri": "https://standard.site",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 71,
                    "byteStart": 56
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 79,
                    "byteStart": 71
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    },
                    {
                      "uri": "https://offprint.app/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 81,
                    "byteStart": 79
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 85,
                    "byteStart": 81
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    },
                    {
                      "uri": "https://pckt.blog/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 128,
                    "byteStart": 85
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 150,
                    "byteStart": 128
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#code"
                    },
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 155,
                    "byteStart": 150
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 180,
                    "byteStart": 155
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#code"
                    },
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 193,
                    "byteStart": 180
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "Update April 2026: Leaflet migrated to the standard.site lexicon (with Offprint, PCKT and others) so my site now references the site.standard.document and site.standard.publication collections."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 22,
                    "byteStart": 15
                  },
                  "features": [
                    {
                      "uri": "https://atproto.com/guides/glossary#record",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 69,
                    "byteStart": 62
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 87,
                    "byteStart": 75
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 97,
                    "byteStart": 92
                  },
                  "features": [
                    {
                      "uri": "https://atproto.com/guides/glossary#blob",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "Then, to fetch records, I had to build XRPC URLs for fetching records from collections, and blobs of binary data (like images):"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "typescript",
              "plaintext": "export function buildRecordsUrl(collection: string, repo: string = ATPROTO_CONFIG.DID): string {\n  return `${ATPROTO_CONFIG.PDS_URL}/xrpc/com.atproto.repo.listRecords?repo=${repo}&collection=${collection}`;\n}\n\nexport function buildBlobUrl(blobRef: string, did: string = ATPROTO_CONFIG.DID): string {\n  return `${ATPROTO_CONFIG.CDN_URL}/img/avatar/plain/${did}/${blobRef}@jpeg`;\n}",
              "syntaxHighlightingTheme": "github-dark-default"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 12,
                    "byteStart": 5
                  },
                  "features": [
                    {
                      "uri": "https://atproto.at/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 19,
                    "byteStart": 16
                  },
                  "features": [
                    {
                      "uri": "https://bsky.app/profile/sri.xyz",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "💚 Taproot by SRI made finding this information a breeze."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 1,
              "plaintext": "Defining Types"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 55,
                    "byteStart": 50
                  },
                  "features": [
                    {
                      "uri": "https://antondevtips.com/blog/the-complete-guide-to-typescript-types",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "Before fetching anything, I needed to define some types that match AT Protocol's data structures."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 36,
                    "byteStart": 25
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "This is where things got really real."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "typescript",
              "plaintext": "export interface ATProtocolBlob {\n  $type: 'blob';\n  ref: {\n    $link: string;\n  };\n  mimeType: string;\n  size: number;\n}\n\nexport interface ATProtocolRecord<T = unknown> {\n  uri: string;\n  cid: string;\n  value: T;\n}\n\nexport interface PublicationValue {\n  name: string;\n  base_path: string;\n  icon?: ATProtocolBlob;\n  description?: string;\n  $type: string;\n}\n\nexport interface DocumentValue {\n  title: string;\n  description?: string;\n  publishedAt: string;\n  publication: string;\n  $type: string;\n}\n\nexport type ATProtocolPublication = ATProtocolRecord<PublicationValue>;\nexport type ATProtocolDocument = ATProtocolRecord<DocumentValue>;\n",
              "syntaxHighlightingTheme": "github-dark-default"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 197,
                    "byteStart": 181
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#code"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 244,
                    "byteStart": 235
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#code"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 267,
                    "byteStart": 263
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#code"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 340,
                    "byteStart": 329
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#code"
                    }
                  ]
                }
              ],
              "plaintext": "This keeps my hooks consistent. They return data, loading state, and potential errors in the same shape. Types are crucial to understanding what I am actually fetching. Looking at PublicationValue, I can see that publications have a base_path and an optional icon. Documents reference their publication by URI and include a publishedAt timestamp."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "Once I had types defined, everything else clicked into place."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 10,
                    "byteStart": 5
                  },
                  "features": [
                    {
                      "uri": "https://pdsls.dev/",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 22,
                    "byteStart": 14
                  },
                  "features": [
                    {
                      "uri": "https://bsky.app/profile/juli.ee",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "💚 PDSls by @Juli.ee makes it soooo easy to explore my Atmosphere data, understand the content (which kept in collections like my blog posts and book reviews) and how their schema are structured."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 1,
              "plaintext": "Fetching Data"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 29,
                    "byteStart": 25
                  },
                  "features": [
                    {
                      "uri": "https://www.w3schools.com/react/react_hooks.asp",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "I also created a generic hook that can fetch my records from any collection in the PDS."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "typescript",
              "plaintext": "  const [data, setData] = useState<ATProtocolRecord<T>[] | null>(null);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState<string | null>(null);\n  \n  useEffect(() => {\n        const fetchRecords = async () => {\n            try {\n                const url = buildRecordsUrl(collection);\n        const response = await fetch(url);\n        const data = await response.json();\n        setData(data.records);\n      } catch (err) {\n                setError(err.message);\n      } finally {\n                setLoading(false);\n      }\n    };\n    fetchRecords();\n  }, [collection]);\n  \n  return { data, loading, error };\n}\n",
              "syntaxHighlightingTheme": "github-dark-default"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 50,
                    "byteStart": 36
                  },
                  "features": [
                    {
                      "uri": "https://joeyreyes.dev/blog/react/fetch-data-on-mount",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 73,
                    "byteStart": 52
                  },
                  "features": [
                    {
                      "uri": "https://medium.com/@abhisingh622000/managing-loading-state-in-react-a-complete-guide-20e8a5370435",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 87,
                    "byteStart": 75
                  },
                  "features": [
                    {
                      "uri": "https://www.developerway.com/posts/how-to-handle-errors-in-react",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "This is just standard React stuff—fetch on mount, handle loading states, catch errors. Nothing fancy 🤷‍♂️ and still broken in places."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 31,
                    "byteStart": 20
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 49,
                    "byteStart": 41
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 85,
                    "byteStart": 74
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 92,
                    "byteStart": 89
                  },
                  "features": [
                    {
                      "uri": "https://atproto.com/specs/at-uri-scheme",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                }
              ],
              "plaintext": "Here's where it got interesting! Leaflet articles reference their Leaflet publication by URI, so I needed to fetch multiple collections, squish them together, and do a little transformation."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "typescript",
              "plaintext": "export function fetchPublications(): FetchResult<Document[]> {\n  const { data: publicationsData } = fetchRecords(ATPROTO_COLLECTIONS.PUBLICATION);\n  const { data: documentsData } = fetchRecords(ATPROTO_COLLECTIONS.DOCUMENT);\n\n  useEffect(() => {\n    // Create a lookup map of publications\n    const publicationMap = new Map();\n    publicationsData.forEach((record) => {\n      publicationMap.set(record.uri, {\n        name: record.value.name,\n        basePath: record.value.base_path,\n        icon: record.value.icon ? buildBlobUrl(record.value.icon.ref.$link) : undefined,\n      });\n    });\n\n    // Match documents with their publications\n    const documents = documentsData\n      .map((record) => {\n        const publication = publicationMap.get(record.value.publication);\n        return {\n          title: record.value.title,\n          description: record.value.description,\n          publishedAt: record.value.publishedAt,\n          articleUrl: `https://${publication.basePath}/${slug}`,\n          publication,\n        };\n      })\n      .sort((a, b) => new Date(b.publishedAt) - new Date(a.publishedAt));\n\n    setData(documents);\n  }, [publicationsData, documentsData]);\n\n  return { data, loading, error };\n}",
              "syntaxHighlightingTheme": "github-dark-default"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 105,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "This is specific to me using Leaflet as my CMS and you may have to do this differently for other sources. "
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 1,
              "plaintext": "Connecting Components"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 58,
                    "byteStart": 48
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "Now, using it in pages is dead simple. Here's a simplified example of how I use it on the writing page on my site, wiring it into a dedicated card component."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.code",
              "language": "typescript",
              "plaintext": "export default function WritingPage() {\n  const { data: documents, loading, error } = fetchPublications();\n  if (loading) return <div>Loading posts...</div>;\n  if (error) return <div>Error: {error}</div>;\n\n  return (\n    <div>\n      {documents.map((doc) => (\n        <CardArticle\n          key={doc.uri}\n          article={{\n            title: doc.title,\n            subtitle: doc.description,\n            articleUrl: doc.articleUrl,\n            publication: doc.publication.name,\n            published: doc.publishedAt,\n          }}\n        />\n      ))}\n    </div>\n  );\n}",
              "syntaxHighlightingTheme": "github-dark-default"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 1,
              "plaintext": "That's it... kinda!"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 204,
                    "byteStart": 145
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "No API keys, no auth flow, no schemas to maintain. Just fetch and render! Maybe there's a better way, but for now, this gives me what I want. Do look at the repo as I skimmed a lot for the sake of brevity in this post which is already quite long."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "src": "https://github.com/renderghost/portfolio/",
              "$type": "pub.leaflet.blocks.website",
              "title": "GitHub - renderghost/portfolio: My design portfolio website",
              "description": "My design portfolio website. Contribute to renderghost/portfolio development by creating an account on GitHub.",
              "previewImage": {
                "$type": "blob",
                "ref": {
                  "$link": "bafkreibiwnvxsrvslnfyrubmf24qk2hwd46og4rit6m6fbvbv3qu7owxx4"
                },
                "mimeType": "image/png",
                "size": 28279
              }
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 1,
              "plaintext": "Benefits for me"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 2,
              "facets": [
                {
                  "index": {
                    "byteEnd": 17,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                }
              ],
              "plaintext": "No vendor lock-in"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 93,
                    "byteStart": 79
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "My content lives on my PDS. If Leaflet disappeared tomorrow (it won't 💚 but hypothetically), I could switch to any other AT Protocol publishing tool or build my own."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 2,
              "facets": [
                {
                  "index": {
                    "byteEnd": 12,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                }
              ],
              "plaintext": "No CMS bills"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "I'm not paying $20-50 a month for a headless CMS. My PDS hosts my content, and reading from it is free. Also, I'm not using any of Leaflet's resources."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 2,
              "facets": [
                {
                  "index": {
                    "byteEnd": 19,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                }
              ],
              "plaintext": "Content portability"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "Because it's all AT Protocol, my writing could theoretically show up in any compatible app. It's genuinely portable in a way that CMS-locked content never is."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 2,
              "facets": [
                {
                  "index": {
                    "byteEnd": 20,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                }
              ],
              "plaintext": "Learning opportunity"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": "Building this taught me way more about web protocols and data fetching than I would have learned using an off-the-shelf CMS."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 2,
              "facets": [
                {
                  "index": {
                    "byteEnd": 7,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                }
              ],
              "plaintext": "Control"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 8,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 28,
                    "byteStart": 20
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "I decide how to use my stuff. No fighting with a another company's  opinions about how things should work for me."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 1,
              "plaintext": "Limitations"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.unorderedList",
              "children": [
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "facets": [
                      {
                        "index": {
                          "byteEnd": 14,
                          "byteStart": 5
                        },
                        "features": [
                          {
                            "$type": "pub.leaflet.richtext.facet#bold"
                          }
                        ]
                      }
                    ],
                    "plaintext": "It's read-only so I have to write on Leaflet, not in my own admin panel."
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "facets": [
                      {
                        "index": {
                          "byteEnd": 18,
                          "byteStart": 11
                        },
                        "features": [
                          {
                            "$type": "pub.leaflet.richtext.facet#bold"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 29,
                          "byteStart": 26
                        },
                        "features": [
                          {
                            "$type": "pub.leaflet.richtext.facet#italic"
                          }
                        ]
                      }
                    ],
                    "plaintext": "There's no caching layer (yet) so every page load hits the PDS (For my low-traffic personal site, this is absolutely fine)."
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "facets": [
                      {
                        "index": {
                          "byteEnd": 19,
                          "byteStart": 10
                        },
                        "features": [
                          {
                            "$type": "pub.leaflet.richtext.facet#bold"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 133,
                          "byteStart": 93
                        },
                        "features": [
                          {
                            "uri": "https://futurism.com/future-society/amazon-aws-internet-down",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      }
                    ],
                    "plaintext": "If my PDS goes down, so does my writing page. I guess the same is true of any 3rd party CMS (especially if it's hosted on AWS amirite 👹)."
                  }
                }
              ]
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 20,
                    "byteStart": 17
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 96,
                    "byteStart": 83
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "I needed to do a LOT of work to understand data structures: It's definitely not as plug-and-play as a traditional CMS. For me, these trade-offs are totally worth it and it was fun to get through it all. "
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 1,
              "plaintext": "Could You Do This?"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 21,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 63,
                    "byteStart": 54
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 96,
                    "byteStart": 86
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "Fuck yeah you could! The AT Protocol documentation is excellent, and the community is incredibly helpful! Use AI if you need to. You don't need to be a professional or expert—I'm not! Push things forwards and try stuff out!"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 27,
                    "byteStart": 0
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 34,
                    "byteStart": 27
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    },
                    {
                      "uri": "https://bsky.app/profile/renderg.host",
                      "$type": "pub.leaflet.richtext.facet#link"
                    }
                  ]
                },
                {
                  "index": {
                    "byteEnd": 62,
                    "byteStart": 34
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#bold"
                    }
                  ]
                }
              ],
              "plaintext": "Leave a comment or @ me on Bluesky if you learn something new."
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "plaintext": ""
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.horizontalRule"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.header",
              "level": 3,
              "plaintext": "Thanks to"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.text",
              "facets": [
                {
                  "index": {
                    "byteEnd": 14,
                    "byteStart": 11
                  },
                  "features": [
                    {
                      "$type": "pub.leaflet.richtext.facet#italic"
                    }
                  ]
                }
              ],
              "plaintext": "This would not exist without the incredible work of others"
            }
          },
          {
            "$type": "pub.leaflet.pages.linearDocument#block",
            "block": {
              "$type": "pub.leaflet.blocks.unorderedList",
              "children": [
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "facets": [
                      {
                        "index": {
                          "byteEnd": 20,
                          "byteStart": 4
                        },
                        "features": [
                          {
                            "uri": "https://bsky.app/profile/atproto.com",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 97,
                          "byteStart": 84
                        },
                        "features": [
                          {
                            "uri": "https://atproto.com",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      }
                    ],
                    "plaintext": "The AT Protocol team for building something genuinely open and well-documented. The official docs are some of the best technical documentation I've encountered."
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "facets": [
                      {
                        "index": {
                          "byteEnd": 7,
                          "byteStart": 0
                        },
                        "features": [
                          {
                            "uri": "https://atproto.at/",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 14,
                          "byteStart": 11
                        },
                        "features": [
                          {
                            "uri": "https://bsky.app/profile/sri.xyz",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 24,
                          "byteStart": 19
                        },
                        "features": [
                          {
                            "uri": "https://pdsls.dev/",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 34,
                          "byteStart": 28
                        },
                        "features": [
                          {
                            "uri": "https://bsky.app/profile/juli.ee",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      }
                    ],
                    "plaintext": "Taproot by Sri and PDSls by Juliet were invaluable for exploring and understanding how my PDS is structured. Being able to visually browse my own data made everything click."
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "facets": [
                      {
                        "index": {
                          "byteEnd": 7,
                          "byteStart": 0
                        },
                        "features": [
                          {
                            "uri": "https://leaflet.pub",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 18,
                          "byteStart": 11
                        },
                        "features": [
                          {
                            "uri": "https://bsky.app/profile/schlage.town",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 26,
                          "byteStart": 20
                        },
                        "features": [
                          {
                            "uri": "https://bsky.app/profile/cozylittle.house",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 37,
                          "byteStart": 32
                        },
                        "features": [
                          {
                            "uri": "https://bsky.app/profile/awarm.space",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      }
                    ],
                    "plaintext": "Leaflet by Brendan, Celine, and Jared for their openness and for building my CMS for free 🤣!"
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "facets": [
                      {
                        "index": {
                          "byteEnd": 13,
                          "byteStart": 0
                        },
                        "features": [
                          {
                            "uri": "https://standard.site/",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      }
                    ],
                    "plaintext": "Standard Site for making the Atmosphere more unified."
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "facets": [
                      {
                        "index": {
                          "byteEnd": 11,
                          "byteStart": 0
                        },
                        "features": [
                          {
                            "uri": "https://bsky.app/profile/danabra.mov",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 102,
                          "byteStart": 72
                        },
                        "features": [
                          {
                            "uri": "https://overreacted.io/open-social",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 177,
                          "byteStart": 158
                        },
                        "features": [
                          {
                            "$type": "pub.leaflet.richtext.facet#bold"
                          }
                        ]
                      }
                    ],
                    "plaintext": "Dan Abramov for the inspiration that we can just do things, and for his excellent guide to AT Protocol that helped me understand the fundamentals and realise I can just do stuff!"
                  }
                },
                {
                  "$type": "pub.leaflet.blocks.unorderedList#listItem",
                  "content": {
                    "$type": "pub.leaflet.blocks.text",
                    "facets": [
                      {
                        "index": {
                          "byteEnd": 28,
                          "byteStart": 0
                        },
                        "features": [
                          {
                            "$type": "pub.leaflet.richtext.facet#italic"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 33,
                          "byteStart": 28
                        },
                        "features": [
                          {
                            "$type": "pub.leaflet.richtext.facet#italic"
                          },
                          {
                            "uri": "https://bsky.app/profile/stefheidihues.bsky.social",
                            "$type": "pub.leaflet.richtext.facet#link"
                          }
                        ]
                      },
                      {
                        "index": {
                          "byteEnd": 171,
                          "byteStart": 33
                        },
                        "features": [
                          {
                            "$type": "pub.leaflet.richtext.facet#italic"
                          }
                        ]
                      }
                    ],
                    "plaintext": "And most importantly, to my girly for being so patient while I wrote this thing at speed while she waited for us to go out for a walk this fine cold Berlin Sunday morning."
                  }
                }
              ]
            }
          }
        ]
      }
    ]
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreiacfnw7d4xyrye3ey36qpzahprnqi6fdbrsfee6ypc7vdfe5zaxn4"
    },
    "mimeType": "image/png",
    "size": 989225
  },
  "bskyPostRef": {
    "cid": "bafyreig3bmckrj6hlzsoibtbjrorhvaxskys4bjrteudcjisjymokf5aee",
    "uri": "at://did:plc:s2rczyxit2v5vzedxqs326ri/app.bsky.feed.post/3m56tzm54vs2a",
    "commit": {
      "cid": "bafyreifx5ecdapwdfu2hkqxssgpt6uqj7ghegla2nk3egdkp2bqsux6meu",
      "rev": "3m56tzmaakf24"
    },
    "validationStatus": "valid"
  },
  "description": "A guide to using your 'everything account' on the AT protocol as your own personal CMS",
  "publishedAt": "2025-11-09T10:01:14.041Z"
}