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.
| 1 | 1 | --- |
|
| 2 | + | import { Image } from "astro:assets"; |
|
| 3 | + | import type { ImageMetadata } from "astro"; |
|
| 4 | + | ||
| 2 | 5 | interface Props { |
|
| 3 | - | images: string[]; |
|
| 6 | + | images: (ImageMetadata | string)[]; |
|
| 4 | 7 | } |
|
| 5 | 8 | ||
| 6 | 9 | const { images } = Astro.props; |
|
| 8 | 11 | ||
| 9 | 12 | <div class="image-collage"> |
|
| 10 | 13 | <div class="collage-grid"> |
|
| 11 | - | {images.map((url, index) => ( |
|
| 14 | + | {images.map((img, index) => ( |
|
| 12 | 15 | <div class="collage-item" data-index={index}> |
|
| 13 | - | <img src={url} alt={`Image ${index + 1}`} loading="lazy" /> |
|
| 16 | + | {typeof img === "string" ? ( |
|
| 17 | + | <img src={img} alt={`Image ${index + 1}`} loading="lazy" /> |
|
| 18 | + | ) : ( |
|
| 19 | + | <Image src={img} alt={`Image ${index + 1}`} loading="lazy" /> |
|
| 20 | + | )} |
|
| 14 | 21 | </div> |
|
| 15 | 22 | ))} |
|
| 16 | 23 | </div> |
|
| 8 | 8 | } |
|
| 9 | 9 | ||
| 10 | 10 | const post = defineCollection({ |
|
| 11 | - | schema: z.object({ |
|
| 12 | - | title: z.string(), |
|
| 13 | - | description: z.string().min(10).max(160), |
|
| 14 | - | publishDate: z.string().transform((str) => new Date(str)), |
|
| 15 | - | tags: z.array(z.string()).default([]).transform(removeDupsAndLowerCase), |
|
| 16 | - | ogImage: z.string().optional(), |
|
| 17 | - | hidden: z.boolean().optional().default(false), |
|
| 18 | - | atUri: z.string().optional(), |
|
| 19 | - | }), |
|
| 11 | + | schema: ({ image }) => |
|
| 12 | + | z.object({ |
|
| 13 | + | title: z.string(), |
|
| 14 | + | description: z.string().min(10).max(160), |
|
| 15 | + | publishDate: z.string().transform((str) => new Date(str)), |
|
| 16 | + | tags: z.array(z.string()).default([]).transform(removeDupsAndLowerCase), |
|
| 17 | + | ogImage: z.union([image(), z.string().url()]).optional(), |
|
| 18 | + | hidden: z.boolean().optional().default(false), |
|
| 19 | + | atUri: z.string().optional(), |
|
| 20 | + | }), |
|
| 20 | 21 | }); |
|
| 21 | 22 | ||
| 22 | 23 | const pages = defineCollection({ |
| 4 | 4 | ||
| 5 | 5 | ## Wallet |
|
| 6 | 6 | ||
| 7 | - |  |
|
| 7 | + |  |
|
| 8 | 8 | ||
| 9 | 9 | My wallet is from Saddleback Leather Company, and their marketing punchline “they’ll want it when you’re dead” has so far been true. I’ve been daily carrying this wallet for over a decade and it’s still going strong. Just one of those pieces of gear that you never have to trade out and I love it. |
|
| 10 | 10 | ||
| 11 | 11 | ## Watches |
|
| 12 | 12 | ||
| 13 | - |  |
|
| 13 | + |  |
|
| 14 | 14 | ||
| 15 | 15 | I have a few watches on rotation ever since my Hamilton Khaki Field Mechanical stopped running (I have plans to fix it myself pending my next hobby adventure). The Vaer S5 Tactical Field in 40mm has been a solid and reliable watch, and it’s hard to beat the classic NATO strap. |
|
| 16 | 16 | ||
| 17 | - |  |
|
| 17 | + |  |
|
| 18 | 18 | ||
| 19 | 19 | I’ve also been getting into Casio watches for the reliability and low cost. The AE1200 aka Casio Royale is probably going to be the one that sticks the most. I often have to travel for work into different time zones and I love the world time feature on this watch. |
|
| 20 | 20 | ||
| 21 | - |  |
|
| 21 | + |  |
|
| 22 | 22 | ||
| 23 | 23 | I also tried the A168WA-1 as it is considered a classic, and while I do like it, the bracelet catches a lot of arm hair. |
|
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | 26 | ## Knife |
|
| 27 | 27 | ||
| 28 | - |  |
|
| 28 | + |  |
|
| 29 | 29 | ||
| 30 | 30 | I have a long history with knife collecting, and as I started to have kids I began to sell more and more as I just wasn’t as interested or in most cases needed the extra cash. I am thankful for this Kershaw Iridium as it checks so many boxes for me, including the lock mechanism, D2 blade steel, titanium handles, overall an amazing deal for $60. |
|
| 31 | 31 | ||
| 32 | 32 | ## Pens |
|
| 33 | 33 | ||
| 34 | - |  |
|
| 34 | + |  |
|
| 35 | 35 | ||
| 36 | 36 | Over the years I've tried so many pens, including various fountain pens. Currently I'm using the Kaweco AL Sport in Anthracite with a fine nib. It's a fantastic little aluminum fountain pen that just feels high quality. My only gripe is that it uses cartridges/converters rather than having a builtin piston mechanism. One time the converter came out of the pen and got ink everywhere, so I might eventually upgrade to Kaweco's AL Piston. I also have a TWSBI Diamond 580ALR which I do love, but it's just a bit large for a pocket pen. |
|
| 37 | 37 | ||
| 38 | - |  |
|
| 38 | + |  |
|
| 39 | 39 | ||
| 40 | 40 | My current ink of choice is Nagasawa Kobe in Museum Grey. It's absolutely lovely and writes so well. |
|
| 41 | 41 | ||
| 42 | 42 | ## Notebook |
|
| 43 | 43 | ||
| 44 | - |  |
|
| 44 | + |  |
|
| 45 | 45 | ||
| 46 | 46 | I've been a Field Notes user for over a decade, and why I like them and the collecting factor, I started to really enjoy MD paper. Then I discovered the Traveler’s Journal system and I was hooked. I currently have a passport size with a single dot grid insert, but I've already gone through two of the basic blank inserts which are nice. Inside I have the Kraft pocket for keeping random notes or stickers. |
|
| 47 | 47 |
| 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/surf-the-web.png" |
|
| 6 | + | ogImage: "../../assets/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/disconnected.jpg" |
|
| 6 | + | ogImage: "../../assets/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 |
| 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/atprotocol.png" |
|
| 6 | + | ogImage: "../../assets/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/back-to-basics.png" |
|
| 6 | + | ogImage: "../../assets/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/base-cover.jpg" |
|
| 6 | + | ogImage: "../../assets/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/guestbook-cover.png" |
|
| 6 | + | ogImage: "../../assets/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/sipp-demo.png" |
|
| 6 | + | ogImage: "../../assets/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/gemini.png" |
|
| 6 | + | ogImage: "../../assets/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/indexing-standard-site.png" |
|
| 6 | + | ogImage: "../../assets/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 | ||
| 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/alcove.jpg" |
|
| 6 | + | ogImage: "../../assets/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/sequoia-hero.png" |
|
| 6 | + | ogImage: "../../assets/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/ai-mentor.png" |
|
| 6 | + | ogImage: "../../assets/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/leaving-neovim-for-zed.png" |
|
| 6 | + | ogImage: "../../assets/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 | ||
| 184 | 184 | } |
|
| 185 | 185 | ``` |
|
| 186 | 186 | ||
| 187 | - |  |
|
| 187 | + |  |
|
| 188 | 188 | ||
| 189 | 189 | ### Plugin Replacements |
|
| 190 | 190 | ||
| 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/programmer-extinction.png" |
|
| 6 | + | ogImage: "../../assets/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/diogenes.png" |
|
| 6 | + | ogImage: "../../assets/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/bear-blog.png" |
|
| 6 | + | ogImage: "../../assets/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/return-to-neovim.png" |
|
| 5 | + | ogImage: "../../assets/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 | ||
| 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/spring-updates.png" |
|
| 6 | + | ogImage: "../../assets/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/standard-site.png" |
|
| 6 | + | ogImage: "../../assets/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/42.png" |
|
| 6 | + | ogImage: "../../assets/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/natspec-contract.png" |
|
| 6 | + | ogImage: "../../assets/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/atproto.png" |
|
| 6 | + | ogImage: "../../assets/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/vibe-coding-kodak.png" |
|
| 6 | + | ogImage: "../../assets/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/ai-ick-og.png" |
|
| 6 | + | ogImage: "../../assets/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 | + | import friend2 from '../../assets/blog-images/friend-2.jpeg' |
|
| 12 | + | import friend3 from '../../assets/blog-images/friend-3.jpeg' |
|
| 13 | + | import friend4 from '../../assets/blog-images/friend-4.jpeg' |
|
| 14 | + | import friend5 from '../../assets/blog-images/friend-5.jpeg' |
|
| 11 | 15 | ||
| 12 | - |  |
|
| 16 | + |  |
|
| 13 | 17 | ||
| 14 | 18 | 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 | 19 | ||
| 16 | 20 | Needless to say, people didn't like it. |
|
| 17 | 21 | ||
| 18 | - | <ImageCollage images={[ |
|
| 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 | - | ]}/> |
|
| 22 | + | <ImageCollage images={[friend2, friend3, friend4, friend5]}/> |
|
| 24 | 23 | ||
| 25 | 24 | ||
| 26 | 25 | It's these kinds of AI innovations that give us the "ick," but why? There's plenty of AI tools we use all the time without much thought, but sometimes we get the feeling that the tech goes "too far." To understand why, we need to step back and ask a few more questions. |
| 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/alacritty.png" |
|
| 6 | + | ogImage: "../../assets/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/jq-cover.webp" |
|
| 6 | + | ogImage: "../../assets/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 | 1 | --- |
|
| 2 | 2 | import type { CollectionEntry } from "astro:content"; |
|
| 3 | + | import { getImage } from "astro:assets"; |
|
| 3 | 4 | ||
| 4 | 5 | import BaseLayout from "./Base.astro"; |
|
| 5 | 6 | import BlogHero from "@/components/blog/Hero.astro"; |
|
| 12 | 13 | const { |
|
| 13 | 14 | data: { title, description, ogImage, publishDate, atUri }, |
|
| 14 | 15 | } = post; |
|
| 15 | - | const socialImage = ogImage ?? "/social-card.png"; |
|
| 16 | + | ||
| 17 | + | let socialImage: string; |
|
| 18 | + | if (!ogImage) { |
|
| 19 | + | socialImage = "/social-card.png"; |
|
| 20 | + | } else if (typeof ogImage === "string") { |
|
| 21 | + | socialImage = ogImage; |
|
| 22 | + | } else { |
|
| 23 | + | const optimized = await getImage({ src: ogImage, format: "png", width: 1200 }); |
|
| 24 | + | socialImage = optimized.src; |
|
| 25 | + | } |
|
| 16 | 26 | const articleDate = publishDate.toISOString(); |
|
| 17 | 27 | const { headings } = await post.render(); |
|
| 18 | 28 | --- |
|