| 81 | 81 | }, |
|
| 82 | 82 | }, |
|
| 83 | 83 | output: "static", |
|
| 84 | - | adapter: cloudflare(), |
|
| 84 | + | adapter: cloudflare({ |
|
| 85 | + | imageService: "compile" |
|
| 86 | + | }), |
|
| 85 | 87 | }); |
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
Binary file — no preview.
| 19 | 19 | }), |
|
| 20 | 20 | }); |
|
| 21 | 21 | ||
| 22 | - | export const collections = { post }; |
|
| 22 | + | const pages = defineCollection({ |
|
| 23 | + | schema: z |
|
| 24 | + | .object({ |
|
| 25 | + | title: z.string().optional(), |
|
| 26 | + | }) |
|
| 27 | + | .optional(), |
|
| 28 | + | }); |
|
| 29 | + | ||
| 30 | + | export const collections = { post, pages }; |
| 3 | 3 | publishDate: "01 Jan 2026" |
|
| 4 | 4 | description: "A small reflection and set of plans for making a ripple in a big lake" |
|
| 5 | 5 | tags: ["open web", "personal"] |
|
| 6 | - | ogImage: "/blog-images/other/surf-the-web.png" |
|
| 6 | + | ogImage: "/blog-images/surf-the-web.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvup73lv2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | I just finished reading [A website to destroy all websites](https://henry.codes/writing/a-website-to-destroy-all-websites/) (if you haven't already you really should), and I'm inspired to put a breath of fresh air into this website which I call home. I've always believed in the importance of having a personal site, and while I have added my own small pieces of flair, I think there's a lot more I can do to help put myself on the page. Currently my website is utilitarian, built to deliver information in a clean way. While I do enjoy the minimal and clean aesthetic, a lot of my own personality gets washed out. Not sure what the changes look like yet, but they will come, and I will have fun :) |
|
| 13 | 13 |
| 3 | 3 | publishDate: "02 May 2023" |
|
| 4 | 4 | description: "I spent two days with zero access to my cell phone or computer, and this is what I discovered" |
|
| 5 | 5 | tags: ["philosophy", "personal"] |
|
| 6 | - | ogImage: "/blog-images/files-stevedylan-dev/disconnected.jpg" |
|
| 6 | + | ogImage: "/blog-images/disconnected.jpg" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvusirgn2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | It was a Thursday afternoon at the chiropractor. I was still on my paternity leave, helping my wife take our kids so our youngest could get some adjustments. Like most dads I sat around, waited, and scrolled on my phone. Halfway through I could tell my wife was miffed, and I thought it was due to our appointment being fifteen minutes late. In reality, my son had been trying to get my attention for several minutes, I ignored him, and he gave up. When she told me later that day I could vividly see it happen, like I was there, but I wasn’t. |
|
| 13 | 13 |
| 6 | 6 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvurvdef2v" |
|
| 7 | 7 | --- |
|
| 8 | 8 | ||
| 9 | - |  |
|
| 9 | + |  |
|
| 10 | 10 | ||
| 11 | 11 | In a [previous blog post](https://stevedylan.dev/posts/why-i-learned-vim) I talked about why I learned Vim, and how it boosted my speed and productivity. In some ways it’s true, but I don’t think I had a grasp on the whole picture. After I watched [this video](https://youtu.be/5wy2iLU5fs0?si=uZ2e6_EUFkrk4Vrp) I realized it wasn’t necessarily just Vim/Neovim, but my terminal based workflow that was at play. I recently gave [Zed](https://zed.dev) another try as it has some attractive features, including [a whole page in their docs dedicated to Vim.](https://zed.dev/docs/vim) It is minimal with Vim keybindings enabled, as well as pretty speedy since its GPU enable and built on Rust. Nevertheless I still felt clumsy, and I realized why: the terminal. With my current terminal workflow I’m able to easily switch between different projects without having multiple code editor windows opened, and I have better access to CLI tools that compliment my developer workflow. I just can’t replicate that outside of the terminal right now. |
|
| 12 | 12 | ||
| 24 | 24 | loop |
|
| 25 | 25 | playsinline |
|
| 26 | 26 | className="aspect-video w-full" |
|
| 27 | - | src="/blog-images/files-stevedylan-dev/tmux-1.mp4" |
|
| 27 | + | src="/blog-images/tmux-1.mp4" |
|
| 28 | 28 | ></video> |
|
| 29 | 29 | ||
| 30 | 30 | Additionally I can create multiple panes and windows inside a session. I generally create a session per project, and each session might have two windows (e.g. one for a client side repo, the other for a server side repo). This both helps keep projects unified yet organized. |
|
| 35 | 35 | loop |
|
| 36 | 36 | playsinline |
|
| 37 | 37 | className="aspect-video w-full" |
|
| 38 | - | src="/blog-images/files-stevedylan-dev/tmux-2.mp4" |
|
| 38 | + | src="/blog-images/tmux-2.mp4" |
|
| 39 | 39 | ></video> |
|
| 40 | 40 | ||
| 41 | 41 | Where it gets really good is having a solid session manager, and that’s where [Josh Medeski’s Sesh](https://github.com/joshmedeski/sesh) comes into play. With this I can easily change between different sessions, and thus easily switch between different projects. This has become essential to my workflow as I often might be working on 2-3 different projects at a time, all with multiple windows and panes each. Each one can be unique to what I’m working on as well. |
|
| 46 | 46 | loop |
|
| 47 | 47 | playsinline |
|
| 48 | 48 | className="aspect-video w-full" |
|
| 49 | - | src="/blog-images/files-stevedylan-dev/sesh.mp4" |
|
| 49 | + | src="/blog-images/sesh.mp4" |
|
| 50 | 50 | ></video> |
|
| 51 | 51 | ||
| 52 | 52 | ## Neovim Plugins |
|
| 61 | 61 | loop |
|
| 62 | 62 | playsinline |
|
| 63 | 63 | className="aspect-video w-full" |
|
| 64 | - | src="/blog-images/files-stevedylan-dev/telescope.mp4" |
|
| 64 | + | src="/blog-images/telescope.mp4" |
|
| 65 | 65 | ></video> |
|
| 66 | 66 | ||
| 67 | 67 | Another one I use fairly often is [Neo-tree](https://github.com/nvim-neo-tree/neo-tree.nvim). I know some people are anti-file-tree but I personally really enjoy it. It is setup to appear in the middle of my screen, and I use it to help navigate where a file might be, edit a file name, add new files, etc. Since the majority of my work is in JavaScript / Next.js, it’s helpful to distinguish which `page.tsx` or `route.ts` file I’m currently working on. |
|
| 72 | 72 | loop |
|
| 73 | 73 | playsinline |
|
| 74 | 74 | className="aspect-video w-full" |
|
| 75 | - | src="/blog-images/files-stevedylan-dev/neotree.mp4" |
|
| 75 | + | src="/blog-images/neotree.mp4" |
|
| 76 | 76 | ></video> |
|
| 77 | 77 | ||
| 78 | 78 | Having an LSP (Language Server Protocol) and completions setup is also essential for a good workflow in Neovim. This is what provides hints, completions, diagnostics, or even docs for the language you’re working in. Cannot state how helpful these are when working in a typed language like Typescript or Go. I would also say it’s beneficial to learn how to set it up manually, and [Typecraft's video](https://youtu.be/S-xzYgTLVJE?si=xG7c-Yx0fkxRHwx0) does a great job showing how it’s done. |
|
| 83 | 83 | loop |
|
| 84 | 84 | playsinline |
|
| 85 | 85 | className="aspect-video w-full" |
|
| 86 | - | src="/blog-images/files-stevedylan-dev/lsp-completions.mp4" |
|
| 86 | + | src="/blog-images/lsp-completions.mp4" |
|
| 87 | 87 | ></video> |
|
| 88 | 88 | ||
| 89 | 89 | These two are on the smaller side but are still really great to use. The first is [Tmux Navigator.](https://github.com/christoomey/vim-tmux-navigator) This allows you to navigate between an open Neovim pane and a Tmux pane without using a Tmux prefix. For example, instead of navigating with `Ctrl + b - l` I can just use `Ctrl - l`. It’s the same mapping for switching between Neovim panes and Tmux panes, which is a huge quality of life improvement. The other small mention is [blame.nvim.](https://github.com/FabijanZulj/blame.nvim) With this tool I can hit `Space-b` to see line by line who changed what when. This is great when working with other people on a project and you’re trying to find out what changed when. There’s also the LazyGit plugin for Neovim, but it deserves its own section. |
|
| 98 | 98 | loop |
|
| 99 | 99 | playsinline |
|
| 100 | 100 | className="aspect-video w-full" |
|
| 101 | - | src="/blog-images/files-stevedylan-dev/lazygit.mp4" |
|
| 101 | + | src="/blog-images/lazygit.mp4" |
|
| 102 | 102 | ></video> |
|
| 103 | 103 | ||
| 104 | 104 | ## Bringing it All Together |
|
| 111 | 111 | loop |
|
| 112 | 112 | playsinline |
|
| 113 | 113 | className="aspect-video w-full" |
|
| 114 | - | src="/blog-images/files-stevedylan-dev/term-walkthrough-1.mp4" |
|
| 114 | + | src="/blog-images/term-walkthrough-1.mp4" |
|
| 115 | 115 | ></video> |
|
| 116 | 116 | ||
| 117 | 117 | If the project has multiple repos like a server/client combo or I’m referencing another repo, I’ll create a new window with the same pane setup. As I work and make changes, I’ll open LazyGit in one of my Tmux panes and run `ctrl-b + z` to make it full screen. From there I’ll add my commits and push them up, or make a branch that I can merge main into if I’m already working on a shared project. |
|
| 122 | 122 | loop |
|
| 123 | 123 | playsinline |
|
| 124 | 124 | className="aspect-video w-full" |
|
| 125 | - | src="/blog-images/files-stevedylan-dev/term-walkthrough-2.mp4" |
|
| 125 | + | src="/blog-images/term-walkthrough-2.mp4" |
|
| 126 | 126 | ></video> |
|
| 127 | 127 | ||
| 128 | 128 | Back in my main Next.js window I might open another split pane below the right one so while the dev server is running I can make test API calls from the terminal with httpie, maybe pipe the results into jq then into a file. |
|
| 133 | 133 | loop |
|
| 134 | 134 | playsinline |
|
| 135 | 135 | className="aspect-video w-full" |
|
| 136 | - | src="/blog-images/files-stevedylan-dev/term-walkthrough-3.mp4" |
|
| 136 | + | src="/blog-images/term-walkthrough-3.mp4" |
|
| 137 | 137 | ></video> |
|
| 138 | 138 | ||
| 139 | 139 | This is the flexibility of a terminal based workflow that is hard to replicate on something like VSCode or Zed. It’s not even an editor issue in my opinion: it’s a development environment issue. Do code editors like VSCode take out out of that environment? Sorta, not totally, but it’s definitely not the same. |
|
| 3 | 3 | publishDate: "21 Jan 2026" |
|
| 4 | 4 | description: "What is the AT Protocol and why does it matter in the grand scheme of the web" |
|
| 5 | 5 | tags: ["atproto", "open web"] |
|
| 6 | - | ogImage: "/blog-images/other/atprotocol.png" |
|
| 6 | + | ogImage: "/blog-images/atprotocol.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvuoqtk52v" |
|
| 8 | 8 | --- |
|
| 9 | 9 |
| 3 | 3 | publishDate: "06 Mar 2026" |
|
| 4 | 4 | description: "Wading my way through the mess that is programming today" |
|
| 5 | 5 | tags: ["programming", "philosophy", "ai"] |
|
| 6 | - | ogImage: "/blog-images/other/back-to-basics.png" |
|
| 6 | + | ogImage: "/blog-images/back-to-basics.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mggpic7sdd2h" |
|
| 8 | 8 | --- |
|
| 9 | 9 |
| 3 | 3 | publishDate: "24 Apr 2025" |
|
| 4 | 4 | description: "My history, experience, concerns, and hope for Base as a viable L2 solution" |
|
| 5 | 5 | tags: [] |
|
| 6 | - | ogImage: "/blog-images/files-stevedylan-dev/base-cover.jpg" |
|
| 6 | + | ogImage: "/blog-images/base-cover.jpg" |
|
| 7 | 7 | hidden: true |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | A couple of weeks ago I watched [Vitalik: An Ethereum Story](https://ethereumfilm.xyz) with my wife, and if you haven't watched it yet I would highly recommend it. The creators did such a good job documenting the life of Ethereum, its creator Vitalik, and the core principles and values surrounding it. A wave of nostalgia took over me as I recalled the feelings I experienced when I watched my first smart contract go live on Rinkeby; a simple and very inefficient store of "posts" like a guestbook. When I saw messages recorded onchain show up on my humble website, I suddenly realized why blockchain and more specifically Ethereum could change everything. It's why I decided to dive into this field of work and why I'm still passionate about it today. |
|
| 13 | 13 | ||
| 25 | 25 | ||
| 26 | 26 | The push of coins is an attempt to rebrand tokens to be just ordinary content. The idea is that instead of posting a photo on socials, turn it into a coin. Every coin can have a photo associated with it, so why not? Instead of "liking" a post you can buy a certain amount. Zora was the first platform making this push as they pivoted from standard NFT posts to coins. I'm not here to convince you whether coins are good for the space or not. Experimentation is part of building onchain and it's how we move forward. The true controversy in my opinion is how Base has been pushing this narrative. |
|
| 27 | 27 | ||
| 28 | - |  |
|
| 28 | + |  |
|
| 29 | 29 | ||
| 30 | 30 | Protocols and tools are built to solve problems. In the case of Ethereum it created a sandbox where the possibilities are endless. Of course Vitalik and the creators had motives for building it, primarily to help democratize internet infrastructure and promote individual autonomy. Outside of some general principles that they believed in, the team was pretty hands off. It was up to the people to decide what they would build. They built things like decentralized governance, tokens, loans, etc. People saw the ways our internet society was broken and came up with solutions only possible because of blockchain and Ethereum. The Ethereum foundation or it's founders don't push people to use it in a certain way, they just provide the tools and let the builders build. |
|
| 31 | 31 | ||
| 32 | - |  |
|
| 32 | + |  |
|
| 33 | 33 | ||
| 34 | 34 | My issue with Base and the coin narrative is that it's pushing a particular agenda and use-case of blockchain. In their opinion it’s how they'll solve the issues they see in the web2 creator economy. That's a big opinion to carry and push upon your followers, and I would argue that it violates the relationship between a blockchain organization and its users. Coins are an interesting experiment, but they're also being pushed by a few individual companies, some that so happen to be financially invested by Coinbase. I want to assume the best of all parties involved, but when it comes to money, capital, and how some people can get absolutely wiped by tokens, the hair on my neck stands up. Vitalik once wrote about what he sees as the values of Ethereum but also the blockchain community at large, and he included the following: |
|
| 35 | 35 | ||
| 3 | 3 | publishDate: "24 Sep 2024" |
|
| 4 | 4 | description: "A quick walkthough of how I built a guestbook for my website" |
|
| 5 | 5 | tags: ["programming", "web development"] |
|
| 6 | - | ogImage: "/blog-images/files-stevedylan-dev/guestbook-cover.png" |
|
| 6 | + | ogImage: "/blog-images/guestbook-cover.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvurhwnn2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | When I was first getting started in web development I remember seeing someone's website and was immediately impressed by one thing: a guestbook. You could sign in with Github and leave a message, similar to someone's Facebook wall back in the day. I thought that was the coolest thing but had no idea how to build it. Fast forward to this weekend, I was reminded how cool that was and I decided to build it for my own website. |
|
| 13 | 13 |
| 3 | 3 | publishDate: "19 Apr 2026" |
|
| 4 | 4 | description: "The good, the bad, and the ugly of using AI to build software" |
|
| 5 | 5 | tags: ["programming", "ai", "philosophy", "personal"] |
|
| 6 | - | ogImage: "/blog-images/other/sipp-demo.png" |
|
| 6 | + | ogImage: "/blog-images/sipp-demo.png" |
|
| 7 | 7 | hidden: false |
|
| 8 | 8 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mjvh4pgklc2q" |
|
| 9 | 9 | --- |
|
| 10 | 10 | ||
| 11 | - |  |
|
| 11 | + |  |
|
| 12 | 12 | ||
| 13 | 13 | For the past month or two I've been experimenting with building personal, self hosted software in Rust. The apps include anything from simple note taking, a wine tracker, image resizing, even a full blown RSS aggregator to replace FreshRSS. I'm not going to go into too much detail around the apps themselves, you can check them out [here](https://andromeda.build) if you're really interested. Instead, I want to use this post to talk about how I got here, why Rust, and the good, the bad, and the ugly of building personal software with AI. |
|
| 14 | 14 |
| 3 | 3 | publishDate: "18 Dec 2025" |
|
| 4 | 4 | description: "A journey down a deep rabbit hole thanks to cassette tapes" |
|
| 5 | 5 | tags: ["open web", "philosophy"] |
|
| 6 | - | ogImage: "/blog-images/other/gemini.png" |
|
| 6 | + | ogImage: "/blog-images/gemini.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvupdcef2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 |
| 3 | 3 | publishDate: "14 Apr 2026" |
|
| 4 | 4 | description: "A journey to index a new standard for content publishing and why it matters" |
|
| 5 | 5 | tags: ["atproto"] |
|
| 6 | - | ogImage: "/blog-images/other/indexing-standard-site.png" |
|
| 6 | + | ogImage: "/blog-images/indexing-standard-site.png" |
|
| 7 | 7 | hidden: false |
|
| 8 | 8 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mjvh4pmxns2q" |
|
| 9 | 9 | --- |
|
| 10 | 10 | ||
| 11 | 11 | import Diagram from "@/components/blog/Diagram.astro" |
|
| 12 | 12 | ||
| 13 | - |  |
|
| 13 | + |  |
|
| 14 | 14 | ||
| 15 | 15 | For decades the internet has been a place to make your voice heard, and the cornerstone for most of that time has been blogs. Even in the rise and fall of social media, blogs continue to have their place in the internet. RSS, as old as it sounds, has also been proven to help connect and keep up with people and their content. However these two pieces of technology have one main problem: distribution. Back in the day, webrings and blogrolls were attempts to help cover this gap, but social media and algorithms became the default way to get that distribution. |
|
| 16 | 16 | ||
| 71 | 71 | ||
| 72 | 72 | That means if we want to properly index Standard.site, we need to first grab the document, then grab the publication. |
|
| 73 | 73 | ||
| 74 | - | <Diagram src="/blog-images/other/standard-site-challenge-1.svg" alt="Diagram showing the standard site challenge workflow between a client and PDS (Personal Data Server). The client requests a document URI (at://document-uri) from the PDS, which returns a document record containing a publication URI (at://publication-uri). The client then requests this publication URI from the PDS, which responds with a publication record containing the site URL." /> |
|
| 74 | + | <Diagram src="/blog-images/standard-site-challenge-1.svg" alt="Diagram showing the standard site challenge workflow between a client and PDS (Personal Data Server). The client requests a document URI (at://document-uri) from the PDS, which returns a document record containing a publication URI (at://publication-uri). The client then requests this publication URI from the PDS, which responds with a publication record containing the site URL." /> |
|
| 75 | 75 | ||
| 76 | 76 | So lets say someone has the document AT URI (something like `at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mii2k5x4hd2h`) then we need to make a total of two API requests at minimum. Not bad, but it gets a bit more complicated. |
|
| 77 | 77 | ||
| 93 | 93 | - Request the publication verification |
|
| 94 | 94 | - Request the main post URL for the document verification |
|
| 95 | 95 | ||
| 96 | - | <Diagram src="/blog-images/other/standard-site-challenge-2.svg" alt="Diagram showing the flow of a standard site challenge. A Client sends an at://document-uri request to a PDS (Personal Data Server). The PDS responds with a document record containing an at://publication-uri. The Client then sends this publication URI back to the PDS, which returns a publication record with a site URL. Finally, the Client makes a GET request to the User's Website/Blog at the path /.well-known/site.standard.publication to complete the verification process." /> |
|
| 96 | + | <Diagram src="/blog-images/standard-site-challenge-2.svg" alt="Diagram showing the flow of a standard site challenge. A Client sends an at://document-uri request to a PDS (Personal Data Server). The PDS responds with a document record containing an at://publication-uri. The Client then sends this publication URI back to the PDS, which returns a publication record with a site URL. Finally, the Client makes a GET request to the User's Website/Blog at the path /.well-known/site.standard.publication to complete the verification process." /> |
|
| 97 | 97 | ||
| 98 | 98 | ||
| 99 | 99 | You can start to see why this is slowly growing in complexity, and unfortunately it only gets worse (we'll get to that later). For now, you can get an idea of what we need to do and the challenges at hand. Let's start talking about some of the solutions I cycled through. |
|
| 118 | 118 | - Queue stores data in D1 database |
|
| 119 | 119 | - Cron job runs to re-check records that were initially marked as not verified |
|
| 120 | 120 | ||
| 121 | - | <Diagram src="/blog-images/other/tap-and-cloudflare.svg" alt="Architecture diagram showing the data flow for a Bluesky content indexing system. The diagram illustrates how new record webhook events flow from Tap (represented by an octagon) through Railway's hosting platform to a Worker service. The Worker processes batches of documents and sends them to both a queue (represented by an oval) and a database (DB, shown as an octagon). The indexed documents are then made available through a GET /feed API endpoint to a Docs.surf application. Additionally, there's a Firehose service (shown as a circle) that connects via WebSocket (wss) to provide real-time data streams. The system also includes PDS (Personal Data Server) and Site/Blog components for record storage and verification processes." /> |
|
| 121 | + | <Diagram src="/blog-images/tap-and-cloudflare.svg" alt="Architecture diagram showing the data flow for a Bluesky content indexing system. The diagram illustrates how new record webhook events flow from Tap (represented by an octagon) through Railway's hosting platform to a Worker service. The Worker processes batches of documents and sends them to both a queue (represented by an oval) and a database (DB, shown as an octagon). The indexed documents are then made available through a GET /feed API endpoint to a Docs.surf application. Additionally, there's a Firehose service (shown as a circle) that connects via WebSocket (wss) to provide real-time data streams. The system also includes PDS (Personal Data Server) and Site/Blog components for record storage and verification processes." /> |
|
| 122 | 122 | ||
| 123 | 123 | Overall this flow worked pretty well! [Docs.surf](https://docs.surf) was born and I was able to build a front-end that could make API calls to the worker which would query the database for complete Standard.site documents. That was until I started blowing through egress limits on Railway when there was a sudden uptick in Standard.site records being created. There was just more and more data being sent out from Railway, and while the cost was manageable, I knew it wouldn't scale at the rate at which records were being created. |
|
| 124 | 124 | ||
| 134 | 134 | ||
| 135 | 135 | Since I already had a full queue flow with a database, it didn't feel necessary to have that Tap database in the way. I could just subscribe to the Jetstream, send the records to the queue, then process the documents. There was the realization that Docs.surf only shows the latest 100 posts, so there's no need to index the entire history of Standard.site records. It was also pointed out that I could subscribe to Jetstream through a [Cloudflare Durable Object](https://developers.cloudflare.com/durable-objects/), therefore keeping all traffic within Cloudflare and avoid ingress or egress fees. |
|
| 136 | 136 | ||
| 137 | - | <Diagram src="/blog-images/other/jetstream-and-cloudflare.svg" alt="Architecture diagram showing data flow between Jetstream, Cloudflare, and various components. The diagram illustrates a Jetstream queue system connected via WebSocket (wss) to a Duable Object, which processes batch documents and records. The flow continues through a Worker that handles database reads and writes, connects to a database (DB), and serves a Docs.surf documentation site. The system processes new record events, manages document verification and indexing, and provides GET /feed endpoints. Additional components shown include a PDS (Personal Data Server) and Site/Blog integration points." /> |
|
| 137 | + | <Diagram src="/blog-images/jetstream-and-cloudflare.svg" alt="Architecture diagram showing data flow between Jetstream, Cloudflare, and various components. The diagram illustrates a Jetstream queue system connected via WebSocket (wss) to a Duable Object, which processes batch documents and records. The flow continues through a Worker that handles database reads and writes, connects to a database (DB), and serves a Docs.surf documentation site. The system processes new record events, manages document verification and indexing, and provides GET /feed endpoints. Additional components shown include a PDS (Personal Data Server) and Site/Blog integration points." /> |
|
| 138 | 138 | ||
| 139 | 139 | The results of the refactor were amazing. By cutting out the external requests from Tap, we were able to bring request volume down dramatically. |
|
| 140 | 140 | ||
| 141 | - |  |
|
| 141 | + |  |
|
| 142 | 142 | ||
| 143 | 143 | Now Docs.surf runs on a single Cloudflare account that only costs $5 a month. It was so refreshing to find a solution that fit my particular use case with the help of the atproto community. |
|
| 144 | 144 | ||
| 3 | 3 | publishDate: "23 Nov 2025" |
|
| 4 | 4 | description: "Pushing forward the consumption of content without the invasion of privacy" |
|
| 5 | 5 | tags: ["open web", "programming"] |
|
| 6 | - | ogImage: "/blog-images/other/alcove.jpg" |
|
| 6 | + | ogImage: "/blog-images/alcove.jpg" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvupi6mf2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 |
| 3 | 3 | publishDate: "30 Jan 2026" |
|
| 4 | 4 | description: "A new CLI tool for publishing existing blogs to the AT Protocol" |
|
| 5 | 5 | tags: ["atproto", "open web"] |
|
| 6 | - | ogImage: "/blog-images/other/sequoia-hero.png" |
|
| 6 | + | ogImage: "/blog-images/sequoia-hero.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvuohmmn2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 |
| 3 | 3 | publishDate: "11 Jul 2025" |
|
| 4 | 4 | description: "A glimpse into a better way of learning to code, where you put the LLM in the backseat while you drive" |
|
| 5 | 5 | tags: ["ai", "programming"] |
|
| 6 | - | ogImage: "/blog-images/files-stevedylan-dev/ai-mentor.png" |
|
| 6 | + | ogImage: "/blog-images/ai-mentor.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvuqzawf2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | I think most developers out there would agree that we're in a bit of an AI hype bubble, yet one piece of AI tech that has recently hit the market which developers can't stop talking about might be different. Of course I'm talking about "agents" like Claude Code or my personal favorite [Opencode](https://opencode.ai). With a few prompts you can have an AI create a plan to implement a feature or fix a bug, and it will just do it. They generally have deep system integration with your terminal and LSPs to have a great understanding of how to build something. However in my opinion these tools, like any other AI tool, are a double edged sword. |
|
| 13 | 13 | ||
| 54 | 54 | ||
| 55 | 55 | When all was said and done, I accomplished my goal of building a fun little CLI called [walletfetch](https://github.com/stevedylandev/walletfetch) that works like Neofetch but for EVM based wallets! |
|
| 56 | 56 | ||
| 57 | - |  |
|
| 57 | + |  |
|
| 58 | 58 | ||
| 59 | 59 | Taking the time to learn this way was super helpful, and I will definitely be doing it more often. It's certainly not perfect, and it's no replacement for core materials like the Rust book, but in my opinion it's a great way to build projects and learn something new. If you're an aspiring developer, I cannot stress this enough: be competent. Always be curious, ask questions, figure out "why," and look to solve problems you really care about. I saw a post on X recently that went something like "quitting software development now due to AI tools is like quitting woodworking because the table saw was invented." It's a tool like anything else, but you've got to know your fundamentals, and you've got to know what to build. Be a woodworker. Be a craftsman. |
|
| 60 | 60 | ||
| 3 | 3 | publishDate: "16 Aug 2024" |
|
| 4 | 4 | description: "A journey through text editors and how I landed on Zed after years of Neovim" |
|
| 5 | 5 | tags: ["programming", "developer tools", "neovim"] |
|
| 6 | - | ogImage: "/blog-images/files-stevedylan-dev/leaving-neovim-for-zed.png" |
|
| 6 | + | ogImage: "/blog-images/leaving-neovim-for-zed.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvurqlyn2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | I think every developer has their own text editor journey and how they landed on the tool they use today. Perhaps I'm a geek but I love those stories. I have a great appreciation for developer tools and the work that goes into them. This post is for the other geeks out there that also care, and I hope my journey and perspective can prompt others to experiment and try developer tools outside their comfort zones. You never know what you might land on and how much you might enjoy it! |
|
| 13 | 13 | ||
| 33 | 33 | ||
| 34 | 34 | One of the biggest things that has stood out to me using Zed so far is how “everything just works.” There are so many features of an IDE or text editor that people take for granted until they have to set it up themselves in something lower level like Neovim. LSP (language server protocol) is certainly one of them. If you’re not familiar it’s the hints or errors that show up while you’re writing up your code, giving you deep insights to your repo on a language level. When you setup LSP in Neovim it’s a lot of work, and sometimes it can be a bit harder to figure out why it might be bugging out. However it does give you way more control and the option to do a lot of customization. With Zed LSP just works. There are configurations you can make to edit some things, but as a whole it just zips out of the box. There are already keybindings for things like “show definition”, “go to definition”, or even code actions. The only downside is outside of an extension you can’t use your own LSP that’s installed on your machine, but there’s always a pretty large language support that I haven’t had this issue yet. |
|
| 35 | 35 | ||
| 36 | - |  |
|
| 36 | + |  |
|
| 37 | 37 | ||
| 38 | 38 | Another piece that’s related to LSP is completions. This is when you’re typing some code and get suggestions for auto completions that quickly fill the rest of the code out. LSPs usually have great auto-completion because they’re aware of the patterns used in that language. Just to be clear we’re not talking about Copilot yet, this is just completions for snippets and LSP. Once again with Zed it just works out of the box, unlike Neovim which ends up requiring several plugins to make it work right. |
|
| 39 | 39 | ||
| 43 | 43 | loop |
|
| 44 | 44 | playsinline |
|
| 45 | 45 | className="aspect-video w-full" |
|
| 46 | - | src="/blog-images/files-stevedylan-dev/completions.mp4" |
|
| 46 | + | src="/blog-images/completions.mp4" |
|
| 47 | 47 | ></video> |
|
| 48 | 48 | ||
| 49 | 49 | Finally there’s Git integrations. What normally required multiple plugins in Neovim is again ready out of the box with Zed, including feature like toggling Git Blame, viewing diffs, and gutter symbols showing the status of edited lines. |
|
| 54 | 54 | loop |
|
| 55 | 55 | playsinline |
|
| 56 | 56 | className="aspect-video w-full" |
|
| 57 | - | src="/blog-images/files-stevedylan-dev/git-integrations.mp4" |
|
| 57 | + | src="/blog-images/git-integrations.mp4" |
|
| 58 | 58 | ></video> |
|
| 59 | 59 | ||
| 60 | 60 | If I had to make a crude comparison, it’s similar to Linux and Apple. Linux will give you far more control over every piece of your software and hardware at the cost of spending time to configure it. Apple will give you less control but it will likely run smoother. |
|
| 87 | 87 | loop |
|
| 88 | 88 | playsinline |
|
| 89 | 89 | className="aspect-video w-full" |
|
| 90 | - | src="/blog-images/files-stevedylan-dev/assistant-panel.mp4" |
|
| 90 | + | src="/blog-images/assistant-panel.mp4" |
|
| 91 | 91 | ></video> |
|
| 92 | 92 | ||
| 93 | 93 | One feature that I think is particularly nice is the inline assistant, where you can select some lines of code and use `ctrl-enter` to trigger a request to be made to your code via the AI assistance configuration mentioned previously. If you like the results then you can confirm and keep coding. |
|
| 98 | 98 | loop |
|
| 99 | 99 | playsinline |
|
| 100 | 100 | className="aspect-video w-full" |
|
| 101 | - | src="/blog-images/files-stevedylan-dev/inline-assistant.mp4" |
|
| 101 | + | src="/blog-images/inline-assistant.mp4" |
|
| 102 | 102 | ></video> |
|
| 103 | 103 | ||
| 104 | 104 | ### Zed ≠ Neovim |
|
| 184 | 184 | } |
|
| 185 | 185 | ``` |
|
| 186 | 186 | ||
| 187 | - |  |
|
| 187 | + |  |
|
| 188 | 188 | ||
| 189 | 189 | ### Plugin Replacements |
|
| 190 | 190 | ||
| 205 | 205 | loop |
|
| 206 | 206 | playsinline |
|
| 207 | 207 | className="aspect-video w-full" |
|
| 208 | - | src="/blog-images/files-stevedylan-dev/tab-switcher.mp4" |
|
| 208 | + | src="/blog-images/tab-switcher.mp4" |
|
| 209 | 209 | ></video> |
|
| 210 | 210 | ||
| 211 | 211 | Speaking of Telescope, one big replacement is project wide search. While Zed doesn't have a fuzzy find feature, the project wide search is excellent. It will show all results in a multibuffer view which is pretty slick, and allows you to jump between that view and the buffer itself pretty easily. |
|
| 216 | 216 | loop |
|
| 217 | 217 | playsinline |
|
| 218 | 218 | className="aspect-video w-full" |
|
| 219 | - | src="/blog-images/files-stevedylan-dev/project-search.mp4" |
|
| 219 | + | src="/blog-images/project-search.mp4" |
|
| 220 | 220 | ></video> |
|
| 221 | 221 | ||
| 222 | 222 | The terminal toggle is pretty similar to something like VSCode but there are some other hidden ways to get a better terminal experience. One of them is a shortcut to toggle the bottom terminal to be full screen, but even better is opening a terminal as a buffer in the main editing view. |
|
| 236 | 236 | loop |
|
| 237 | 237 | playsinline |
|
| 238 | 238 | className="aspect-video w-full" |
|
| 239 | - | src="/blog-images/files-stevedylan-dev/center-terminal.mp4" |
|
| 239 | + | src="/blog-images/center-terminal.mp4" |
|
| 240 | 240 | ></video> |
|
| 241 | 241 | ||
| 242 | 242 | One of the big things I had to leave behind was Tmux and switching projects. While it isn't a perfect replacement, Zed has a "switch projects" feature which works really well and makes it pretty easy to switch contexts. You just won't get the exact same control and layout setup that you can get with Tmux |
|
| 261 | 261 | loop |
|
| 262 | 262 | playsinline |
|
| 263 | 263 | className="aspect-video w-full" |
|
| 264 | - | src="/blog-images/files-stevedylan-dev/switch-projects.mp4" |
|
| 264 | + | src="/blog-images/switch-projects.mp4" |
|
| 265 | 265 | ></video> |
|
| 266 | 266 | ||
| 267 | 267 | ## Should You Use Zed? |
|
| 3 | 3 | publishDate: "27 Feb 2026" |
|
| 4 | 4 | description: "Examining the parallels between art, AI, and the existential threat to programmers" |
|
| 5 | 5 | tags: ["ai", "programming", "philosophy"] |
|
| 6 | - | ogImage: "/blog-images/other/programmer-extinction.png" |
|
| 6 | + | ogImage: "/blog-images/programmer-extinction.png" |
|
| 7 | 7 | hidden: false |
|
| 8 | 8 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mfv2rjkplk2h" |
|
| 9 | 9 | --- |
| 3 | 3 | publishDate: "16 Oct 2025" |
|
| 4 | 4 | description: "Realizing how much of the programming space is just bowls" |
|
| 5 | 5 | tags: ["programming", "philosophy"] |
|
| 6 | - | ogImage: "/blog-images/other/diogenes.png" |
|
| 6 | + | ogImage: "/blog-images/diogenes.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvuposjn2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | One of my favorite videos I watched recently was by Pewdiepie, and while the title is ["help, Im going through a midlife crisis..."](https://www.youtube.com/watch?v=n_Lv_mw6m6c), you realize about 3/4 of the way through that it was just bait. The real topic of the video is minimalism, and a great story about the philosopher Diogenes and his bowl. Diogenes was known for only having a single possession to his name: a wooden bowl. One day as he was walking he saw a child by the river drinking the water by cupping his hands together. It was in this moment Diogenes realized that his bowl was useless since he had his hands, and he threw away his bowl. It was the ultimate commitment to the principles he believed, that true happiness was not found in wealth or possessions. You should watch the video because 1. Pewdiepie tells the story way better than I do and with a lot more humor, and 2. he articulates how he's carried out the principles of minimalism in his own life and living by principle. |
|
| 13 | 13 |
| 3 | 3 | publishDate: "23 Sep 2025" |
|
| 4 | 4 | description: "Let's go back to when social media was about people" |
|
| 5 | 5 | tags: ["open web", "philosophy"] |
|
| 6 | - | ogImage: "/blog-images/other/bear-blog.png" |
|
| 6 | + | ogImage: "/blog-images/bear-blog.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvuqbfav2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | Recently a local news station in Maine reported a story of some middle schoolers calling their friends with landline telephones. Their parents thought they were too young for cell phones and wanted to hold off on that aspect of reality, so they got an old phone from the 90s, and soon their friends also got phones. It formed schedules of calls they would make to talk to each other, even creating a phone ring of contacts. |
|
| 13 | 13 |
| 2 | 2 | title: "Returning to Neovim" |
|
| 3 | 3 | publishDate: "16 Mar 2026" |
|
| 4 | 4 | description: "Once again coming back to the editor I can't shake" |
|
| 5 | - | ogImage: "/blog-images/other/return-to-neovim.png" |
|
| 5 | + | ogImage: "/blog-images/return-to-neovim.png" |
|
| 6 | 6 | tags: ["programming", "neovim", "developer"] |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mjvh4prebs2q" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | One of my more popular blog posts was how and why I switched to [Zed from Neovim](https://stevedylan.dev/posts/leaving-neovim-for-zed/). That was almost two years ago, and in that period Zed was my daily driver for programming. Every now and then I would still use Neovim to edit a config or make a quick edit, but outside of that, Zed was where I lived. It performed admirably, with minimal bugs that only irked me from time to time that would eventually be fixed. AI was still relatively minimal and I enjoyed using it. So why go back to Neovim? |
|
| 13 | 13 | ||
| 143 | 143 | ||
| 144 | 144 | The key is `vim.lsp.enable()` where we pass in the names of all our files that have configs. Everything else is just some nicer configuration for looking at diagnostics. |
|
| 145 | 145 | ||
| 146 | - |  |
|
| 146 | + |  |
|
| 147 | 147 | ||
| 148 | 148 | It's that simple, and I absolutely love how minimal the experience is. Does require understanding what your LSPs are, where they live, and how to run them, but totally worth it. |
|
| 149 | 149 | ||
| 166 | 166 | loop |
|
| 167 | 167 | playsinline |
|
| 168 | 168 | className="w-full aspect-video" |
|
| 169 | - | src="/blog-images/other/mini-completion.mp4" |
|
| 169 | + | src="/blog-images/mini-completion.mp4" |
|
| 170 | 170 | ></video> |
|
| 171 | 171 | ||
| 172 | 172 | This would normally be handled through something heavier like coc.nvim, but it's truly awesome to have a simple and lightweight option inside mini.nvim. |
|
| 179 | 179 | loop |
|
| 180 | 180 | playsinline |
|
| 181 | 181 | className="w-full aspect-video" |
|
| 182 | - | src="/blog-images/other/mini-files.mp4" |
|
| 182 | + | src="/blog-images/mini-files.mp4" |
|
| 183 | 183 | ></video> |
|
| 184 | 184 | ||
| 185 | 185 | A minimal file explorer thats a fun mix between oil and netrw. |
|
| 192 | 192 | loop |
|
| 193 | 193 | playsinline |
|
| 194 | 194 | className="w-full aspect-video" |
|
| 195 | - | src="/blog-images/other/mini-pick-files.mp4" |
|
| 195 | + | src="/blog-images/mini-pick-files.mp4" |
|
| 196 | 196 | ></video> |
|
| 197 | 197 | ||
| 198 | 198 | Pick anything. Actually though. In a lot of ways this replaces telescope and lets me fuzzy find files, buffers, you name it! |
|
| 225 | 225 | loop |
|
| 226 | 226 | playsinline |
|
| 227 | 227 | className="w-full aspect-video" |
|
| 228 | - | src="/blog-images/other/buffers.mp4" |
|
| 228 | + | src="/blog-images/buffers.mp4" |
|
| 229 | 229 | ></video> |
|
| 230 | 230 | ||
| 231 | 231 | I don't have tabs setup in Neovim as I started to realize I don't really need them. I can use my keyboard shortcuts to move between buffers horizontally, |
|
| 256 | 256 | loop |
|
| 257 | 257 | playsinline |
|
| 258 | 258 | className="w-full aspect-video" |
|
| 259 | - | src="/blog-images/other/nvim-diagnostics.mp4" |
|
| 259 | + | src="/blog-images/nvim-diagnostics.mp4" |
|
| 260 | 260 | ></video> |
|
| 261 | 261 | ||
| 262 | 262 | Nothing too fancy here but it is nice how versatile the experience can be. I can either use this keymap to do a hover diagnostic: |
|
| 279 | 279 | loop |
|
| 280 | 280 | playsinline |
|
| 281 | 281 | className="w-full aspect-video" |
|
| 282 | - | src="/blog-images/other/nvim-find.mp4" |
|
| 282 | + | src="/blog-images/nvim-find.mp4" |
|
| 283 | 283 | ></video> |
|
| 284 | 284 | ||
| 285 | 285 | One of the most important things an editor needs is an easy way to find anything, and I'm quite pleased with what I have setup here. To start, if I wanted to search the entire codebase for a given string, I can use mini.pick with `live_grep`. |
|
| 3 | 3 | publishDate: "26 Apr 2026" |
|
| 4 | 4 | description: "Some fun updates I've made to my personal website" |
|
| 5 | 5 | tags: ["personal", "open web" ] |
|
| 6 | - | ogImage: "/blog-images/other/spring-updates.png" |
|
| 6 | + | ogImage: "/blog-images/spring-updates.png" |
|
| 7 | 7 | hidden: false |
|
| 8 | 8 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mkgvv37nsk2q" |
|
| 9 | 9 | --- |
|
| 10 | 10 | ||
| 11 | - |  |
|
| 11 | + |  |
|
| 12 | 12 | ||
| 13 | 13 | Earlier this week I quietly released an iOS app called [scout](https://apps.apple.com/us/app/scout-smallnet-browser/id6762810515), a Gemini protocol client. I built it quite a while ago but never published, and thought "why not?" Almost immediately after doing so, I read [this post](https://xn--gckvb8fzb.com/gemini-is-solutionism-at-its-worst/) that really made me think about the Gemini approach in general. After some deliberation, I thought it would be good to pour more into my personal site and invest in HTTP. The results have been so much fun, and I haven't been able to stop making changes all week! Here's a few highlights. |
|
| 14 | 14 |
| 3 | 3 | publishDate: "11 Jan 2026" |
|
| 4 | 4 | description: "Another deep exploration into ATProto and implementing lexicons" |
|
| 5 | 5 | tags: ["atproto", "open web"] |
|
| 6 | - | ogImage: "/blog-images/other/standard-site.png" |
|
| 6 | + | ogImage: "/blog-images/standard-site.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvuovxm52v" |
|
| 8 | 8 | --- |
|
| 9 | 9 |
| 3 | 3 | publishDate: "15 Aug 2025" |
|
| 4 | 4 | description: "42? Sorta, but not exactly" |
|
| 5 | 5 | tags: ["personal", "philosophy"] |
|
| 6 | - | ogImage: "/blog-images/files-stevedylan-dev/42.png" |
|
| 6 | + | ogImage: "/blog-images/42.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvuqqzav2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | Even if you haven't read the book or seen the movie, you are likely familiar with the famous yet humorous answer to the meaning of life: 42. Just a number. The original author didn't intend any deeper meaning and stresses that it means nothing. Ironically I think like everything in life, it holds an ounce of truth beyond what we see in it. |
|
| 13 | 13 |
| 3 | 3 | publishDate: "31 Aug 2025" |
|
| 4 | 4 | description: "An exploration on how NatSpec could be used to not only maintain context but provide user interfaces" |
|
| 5 | 5 | tags: ["programming", "blockchain"] |
|
| 6 | - | ogImage: "/blog-images/files-stevedylan-dev/natspec-contract.png" |
|
| 6 | + | ogImage: "/blog-images/natspec-contract.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvuqmxen2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | One of the most common problems encountered when building decentralized applications is the disconnect between the smart contract and the client. A normal flow might look something like this: |
|
| 13 | 13 | ||
| 201 | 201 | ||
| 202 | 202 | As a result we get a nice page that not only has markdown formatting but interactive UI components that are built in thanks to Markdown UI. |
|
| 203 | 203 | ||
| 204 | - |  |
|
| 204 | + |  |
|
| 205 | 205 | ||
| 206 | 206 | I took a little extra time to add in Wagmi to the app which resulted in a fully interactive contract, which you can check out [here](https://natspec-ui.orbiter.website). In a sense we achievied the goal of a unified standard markup that can make user interactions with contracts easier. Of course we have to keep in mind the limitations here, primarily being it would require developers to make sure they include all of this markup in their contract and the Markdown UI standard isn't even out of a beta stage, and for that reason I would highly recommend a professional solution like the Contracts UI Builder. Nevertheless it's fun to see how extensible and open Markdown and Solidity have come in the past few years. Each day we're getting closer to an internet that is not only safe, but user friendly as well. |
|
| 207 | 207 | ||
| 3 | 3 | publishDate: "05 Jan 2026" |
|
| 4 | 4 | description: "My little weekend experiment to bring micro updates to my personal site" |
|
| 5 | 5 | tags: ["atproto", "open web"] |
|
| 6 | - | ogImage: "/blog-images/other/atproto.png" |
|
| 6 | + | ogImage: "/blog-images/atproto.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvup2mzf2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 |
| 3 | 3 | publishDate: "30 Mar 2025" |
|
| 4 | 4 | description: "A perspective on the rise of AI coding and how it relates to technological shifts throughout history" |
|
| 5 | 5 | tags: ["programming", "ai"] |
|
| 6 | - | ogImage: "/blog-images/files-stevedylan-dev/vibe-coding-kodak.png" |
|
| 6 | + | ogImage: "/blog-images/vibe-coding-kodak.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvur3ysv2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | I'm sure many who read this are familiar by now with the term "vibe coding," a euphoric style of programming where you prompt AI models or IDEs to write software and just "vibe." One of the more popular instances that made the practice takeoff was the indie hacker Levelsio building a flight simulator entirely in JavaScript and selling ad space within the game. Others have followed suit and even started businesses by vibe coding them into existence. It's hard to deny the reality that AI has been changing much of the software ecosystem, and with any major shift in technology there are lots of opinions. I certainly have my own, but I thought it would be more productive to look at history repeat itself. |
|
| 13 | 13 | ||
| 15 | 15 | ||
| 16 | 16 | Most people don't know it, but there was a major controversy in the world of photography in the year 1900. Before that time photography was an art form protected by its sages, who poured their money, time, and practice into it. Not anyone could just take a picture, only those who had worked in the craft and mastered it. All of that changed in February of 1900 when Kodak released the Brownie camera. It wasn't much to look at, a little cardboard box that could take a picture no bigger than 2.25 inches using 117mm film. What made it special was the service behind it. The Brownie only cost $1 (which would be $38 at the time of this post), and it included the cost to develop the film. All someone had to do was take a picture, send it off to Kodak, and they would return the picture. "You press the button—we do the rest." |
|
| 17 | 17 | ||
| 18 | - |  |
|
| 18 | + |  |
|
| 19 | 19 | ||
| 20 | 20 | Suddenly anyone could take photos: parents, grandparents, kids, truly anyone. It sold like crazy, and it upset the old photographer guild. There was great concern that there would now be a huge amount of "slop" photography and the art of photography would be washed away. Surely no one who took photos in such a way could be an artist... right? These artists were also concerned for their profession. If everyone had a camera, why would families pay for a photography session? |
|
| 21 | 21 | ||
| 33 | 33 | ||
| 34 | 34 | The evolution of photography technology enabled plenty of bad photos and photographers, but it also created a whole new series of artists we would not have otherwise. One of my favorite examples of this is Vivian Maier. If you're not familiar, Vivian Maier was an unknown nanny in the 1940's and 50's. It wasn't until after her death that her life's work as a photographer was discovered by a man who won it at an auction. To his surprise it was a stunning collection, hundreds of thousands of them, all taken by a nanny no one had ever heard of. She was passionate about photography, and her perspectives of the world at that time were unique. |
|
| 35 | 35 | ||
| 36 | - |  |
|
| 36 | + |  |
|
| 37 | 37 | ||
| 38 | 38 | They're made possible thanks to the much later successor of a Brownie style camera that she could take everywhere and shoot roll after roll of film. If photography was still stuck in the dark ages of carrying around big pieces of equipment that only certain people could afford, we wouldn't have the stunning work of Vivian Maier. |
|
| 39 | 39 | ||
| 40 | - |  |
|
| 40 | + |  |
|
| 41 | 41 | ||
| 42 | 42 | Another unrecognized photographer is one of my favorites, Joe Greer. Greer started his career on an app: Instagram. He didn't take photography lessons, he didn't have a nice camera, he just had his phone. The more and more he shot with his phone and posted his photos on Instagram, the more people liked them and the bigger it got. Eventually he did switch to professional cameras and continued his craft, but the key was his access to an art form that otherwise wouldn't be available apart from cell phone cameras. |
|
| 43 | 43 | ||
| 44 | - |  |
|
| 44 | + |  |
|
| 45 | 45 | ||
| 46 | 46 | In the realm of programming, even in the evolution of languages, we see a similar pattern where mediocrity increases but so does the number of discovered programmers. Sure there's a lot of Javascript slop out there, but thanks to Javascript there have been more and more people discovering programming and starting a wonderful journey. You don't have to start in a lower language to find the joy of programming, and most people who do find it will experiment in many different languages. |
|
| 47 | 47 | ||
| 3 | 3 | publishDate: "3 Oct 2025" |
|
| 4 | 4 | description: "Ever look at something made by an AI company that gives you the 'ick'?" |
|
| 5 | 5 | tags: ["ai", "philosophy"] |
|
| 6 | - | ogImage: "/blog-images/other/ai-ick-og.png" |
|
| 6 | + | ogImage: "/blog-images/ai-ick-og.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvuq2x752v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | 10 | import ImageCollage from '@/components/common/ImageCollage' |
|
| 11 | 11 | ||
| 12 | - |  |
|
| 12 | + |  |
|
| 13 | 13 | ||
| 14 | 14 | A few days ago OpenAI released Sora, which was not only the latest version of their video generation model, but also a social app. Humans sign up, but the only content is that generated by users through AI. If you're like me, the very thought of an AI-only generated feed might have given you the "ick." It's not the first time either. The debut of Friend (an AI powered "friend" app / pendant you wear around your neck) got even more backlash recently with their NYC subway ads. |
|
| 15 | 15 | ||
| 16 | 16 | Needless to say, people didn't like it. |
|
| 17 | 17 | ||
| 18 | 18 | <ImageCollage images={[ |
|
| 19 | - | '/blog-images/other/friend-2.jpeg', |
|
| 20 | - | '/blog-images/other/friend-3.jpeg', |
|
| 21 | - | '/blog-images/other/friend-4.jpeg', |
|
| 22 | - | '/blog-images/other/friend-5.jpeg', |
|
| 19 | + | '/blog-images/friend-2.jpeg', |
|
| 20 | + | '/blog-images/friend-3.jpeg', |
|
| 21 | + | '/blog-images/friend-4.jpeg', |
|
| 22 | + | '/blog-images/friend-5.jpeg', |
|
| 23 | 23 | ]}/> |
|
| 24 | 24 | ||
| 25 | 25 |
| 3 | 3 | publishDate: "05 Jan 2024" |
|
| 4 | 4 | description: "A brief look at my history and how ordinary jobs lead to learning programming and Vim/Neovim" |
|
| 5 | 5 | tags: ["programming", "neovim"] |
|
| 6 | - | ogImage: "/blog-images/files-stevedylan-dev/alacritty.png" |
|
| 6 | + | ogImage: "/blog-images/alacritty.png" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvurxbuf2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | Something I see pretty consistently when the topic of Vim/Neovim comes up is the inevitable question "Why?" Thanks to years of memes about not being able to quit Vim, it has gained a cult popularity of being "elite," "ancient," or both. Most developers who are comfortable in their VSCode environment can't imagine using something so unfriendly and perhaps ugly. So yeah, "why" is a fair question. I reflected on that question and I realized how my own life experience led me to learn Vim, and perhaps it would be helpful to share that story. |
|
| 13 | 13 |
| 3 | 3 | publishDate: "12 Oct 2024" |
|
| 4 | 4 | description: "Discover why learning jq isn't just about boosting your productivity, it's about becoming a more curious developer" |
|
| 5 | 5 | tags: ["programming", "developer tools"] |
|
| 6 | - | ogImage: "/blog-images/files-stevedylan-dev/jq-cover.webp" |
|
| 6 | + | ogImage: "/blog-images/jq-cover.webp" |
|
| 7 | 7 | atUri: "at://did:plc:ia2zdnhjaokf5lazhxrmj6eu/site.standard.document/3mdzvurdwpv2v" |
|
| 8 | 8 | --- |
|
| 9 | 9 | ||
| 10 | - |  |
|
| 10 | + |  |
|
| 11 | 11 | ||
| 12 | 12 | The chances are that if you are a modern developer or if you're starting out, you probably don't know what `jq` is, and that's why I'm writing this post. It won't take long to explain what `jq` is, so let's just get that out of the way. |
|
| 13 | 13 |
| 1 | - | import { OWNER_DID } from "@/data/constants"; |
|
| 2 | - | ||
| 3 | - | export const prerender = true; |
|
| 4 | - | ||
| 5 | - | const PUBLICATION_RKEY = "3mbykzswhqc2x"; |
|
| 6 | - | ||
| 7 | - | export async function GET() { |
|
| 8 | - | const atUri = `at://${OWNER_DID}/site.standard.publication/${PUBLICATION_RKEY}`; |
|
| 9 | - | ||
| 10 | - | return new Response(atUri, { |
|
| 11 | - | status: 200, |
|
| 12 | - | headers: { |
|
| 13 | - | "Content-Type": "text/plain", |
|
| 14 | - | }, |
|
| 15 | - | }); |
|
| 16 | - | } |