Skip to content
Frontend Feeds
  • Today
  • Archive
  • Sources
  • Categories
    • The Giants6 Sources
    • Multi Author Blogs18 Sources
    • Top Front-end Bloggers25 Sources
    • More Front-end Bloggers77 Sources
    • Browsers, engines, etc.11 Sources
    • Libraries, Frameworks, etc.12 Sources
    • Company/Startup Blogs12 Sources
    • Developer/Designer News4 Sources
    • YouTube Channels13 Sources
    • Podcasts7 Sources

Category

More Front-end Bloggers

77 Sources
  • Adam Silver
  • Adrian Roselli
  • Ahmad Shadeed
  • Aleksandr Hovhannisyan
  • Ana Rodrigues
  • Andy Bell
  • Ashley Nolan
  • Ben Frain
  • Ben McCormick
  • Ben Myers
  • Better Web Type
  • Big Medium
  • Bram.us
  • Bruce Lawson's personal site
  • Chen Hui Jing
  • CSS Articles by Temani Afif
  • CSS In Real Life
  • Dan Davies
  • Darek Kay
  • Dave Ceddia
  • David Bushell
  • DigitalA11Y
  • DXD
  • Eric Portis
  • Flavio Copes
  • Frontend Masters Blog
  • Geoff Graham
  • Harry Cresswell
  • HeydonWorks
  • Hidde's blog
  • Jack Franklin
  • James Sinclair
  • Jeffrey Zeldman Presents
  • Jim Fisher’s blog
  • Jim Nielsen’s Blog
  • Jonnie Hallman
  • Josh Comeau's blog
  • Julia Evans
  • justmarkup
  • Kilian Valkhof
  • Kitty Giraudel
  • Krasimir Tsonev
  • localghost
  • Manuel Matuzović
  • Marius Schulz
  • Mark's Dev Blog
  • Max Böck
  • Max Stoiber's Essays
  • Mike Taylor
  • Modern Web Development with Chrome
  • Monica Dinculescu
  • Perishable Press
  • Phil Nash
  • Piccalilli
  • raganwald
  • Remote Synthesis
  • Rob Dodson
  • Robin Osborne
  • Robin Wieruch
  • Ryan Mulligan
  • Salma Alam-Naylor
  • Samuel Kraft
  • Sarah Fossheim's Blog
  • Scott Hanselman's Blog
  • Scott O’Hara
  • Set Studio
  • Stéphanie Walter
  • Swizec Teller
  • swyx
  • Tan Li Hau's Blog
  • Tania Rascia
  • text/plain
  • The Code Barbarian
  • The Web Witch's Blog
  • Thoughts From Eric
  • Trys Mudford's Blog
  • Zell Liew

Sunday, 1 November 2026

  • David BushellMore Front-end Bloggers4 min read

    Tangled, hire a front-end accessibility expert

    Not me, this is just friendly advice from a struggling user. Alongside Codeberg I’d consider Tangled to be a real GitHub replacement. We desperately need to leave GitHub behind. It’s difficult to recommend any tech these days. I used to spread the gospel of Proton and that backfired. […]

  • Stéphanie WalterMore Front-end Bloggersread at source

    Pixels of the Week – November 1, 2026

    This week sadly explores how buying online became a nightmare, from deceptive patterns to AI slop. Also, don't miss a fun history guessing game, colorful tufting art, and a book on feminist approaches to type, and my Golden Honey Suckle color.

  • Flavio CopesMore Front-end Bloggersread at source

    What to do when an AI tool exposes your provider keys

    Respond to exposed AI provider keys: revoke the credentials at their source, inspect usage, replace shared access, and distinguish alerts from hard limits.

  • Flavio CopesMore Front-end Bloggersread at source

    How to package and publish an OpenCode plugin

    Package an OpenCode v2 plugin for npm, inspect the tarball, test it in a clean consumer project, and prepare a public release with clear compatibility.

  • Kitty GiraudelMore Front-end Bloggers4 min read

    Playing with CSS Layers

    A short piece to share that I’ve implemented CSS layers on my website, and the few things I’ve learned on the way.

Saturday, 31 October 2026

  • Darek KayMore Front-end Bloggersread at source

    This RSS feed has moved to a new domain

    I've moved my website to a new domain. Please update the URL in your feed reader.

  • Flavio CopesMore Front-end Bloggersread at source

    How to run an LLM locally on macOS, Linux, and Windows

    Explore the ways to run LLMs locally on macOS, Linux, and Windows: desktop apps, terminal tools, browser models, libraries, and self-hosted servers.

  • Flavio CopesMore Front-end Bloggersread at source

    Proton's AI manifesto and what it means to lead coding agents

    Proton's CTO told engineers their job is to help the LLM write code. Where his manifesto is right, where the pushback is fair, and what leading agents involves.

  • Flavio CopesMore Front-end Bloggersread at source

    Void, vinext, or React Router for a Cloudflare app?

    Choose a Cloudflare full-stack setup by following a request, a database change, and a deployment through Void, vinext, and React Router.

  • Flavio CopesMore Front-end Bloggersread at source

    Try Muse Spark Open in OpenCode through Ollama Cloud

    Launch Muse Spark Open in OpenCode through Ollama Cloud, try a bounded JavaScript fix, and check model access, tool use, context, and billing.

  • Flavio CopesMore Front-end Bloggersread at source

    Test your SaaS replacement before cancelling the original

    Run a homemade SaaS replacement beside the original with read-only inputs, compare real outputs, and rehearse recovery before switching over.

  • Flavio CopesMore Front-end Bloggersread at source

    How to make it easy to leave your SaaS

    Design a useful SaaS export with stable IDs, attachments, and import checks, then handle account deletion through a durable, verifiable process.

Friday, 30 October 2026

  • Geoff GrahamMore Front-end Bloggers1 min read

    New Album: Gone Dark

    I worked on a new album this past year as a follow-up to last year’s Covers. I finished it early September, submitted it for distribution, and then… nothing. It sat quietly in “approval” hell. But Gone Dark came out Monday which just so happened to be a very big day for a very different reason. […]

  • Flavio CopesMore Front-end Bloggersread at source

    Build or buy calculator: when does your replacement cost less?

    Compare a SaaS bill with building your own replacement. Count development, migration, maintenance, and overlap to estimate the first cheaper month.

  • Flavio CopesMore Front-end Bloggersread at source

    Research keywords through OpenSEO MCP

    Connect OpenCode to OpenSEO, verify the project and search market, approve a bounded keyword lookup, and save only the ideas you select.

  • Frontend Masters BlogMore Front-end Bloggers13 min read

    Two Circles, One Connection, and border-shape

    Swapping the clip-path arrow from the previous article for border-shape and shape(), we can connect two draggable circles with fancy curved lines that stay perfectly aligned.

  • Flavio CopesMore Front-end Bloggersread at source

    Build a tiny site-audit crawler with Workers and Queues

    Build a bounded Cloudflare crawler with Workers, Queues, and D1 to find broken pages, missing titles, and redirect chains in a local test site.

  • Flavio CopesMore Front-end Bloggersread at source

    The best voice to text apps for a Mac

    Handy is the free open source dictation app I use. Compare the other Mac voice to text apps and speech APIs, then dictate a prompt.

  • PiccalilliMore Front-end Bloggersread at source

    The Index: Issue #204

    CSS-Tricks has a new owner! This really is a big win for the web and it should fill you with hope. We're not done yet ! The Serotonium — Music shared with friends This does exactly what is says on the tin and the volume of extremely good recommendations is mind-blowing. Anthropic files its ‘IPO’ — but all the key numbers are missing If the immediate glazing of Anthropic's IPO documents on social media was getting you down, then have a read to get yourself back level again. Digital recipe management for fastidious cooks An interesting look into the world of managing your recipes and what options there are. Local Wikipedia This is such a cool tool that allows you to filter Wikipedia by your chosen location. CSS nesting: use with caution Here's one from the Piccalilli archives that you might have missed to wrap up this issue. P.S. this is a good website . Sponsor message When anyone can make anything, we can make you stand out. AI technologies have given anyone the ability to bring their ideas to life, but to produce a high quality service that actually works for the people it needs to work for requires experience, specialist skills and creativity. We’ve got heaps of all of that here at Set Studio and we've got availability starting in 2027, so check us out and see what we're about. Check out our work

  • Flavio CopesMore Front-end Bloggersread at source

    Build an agent approval flow that survives a restart

    Build a local approval queue with exact message previews, expiring decisions, rejection, and crash recovery. Test it safely with a fake email provider.

  • Flavio CopesMore Front-end Bloggersread at source

    Lessons for builders from Sam Altman's Cheeky Pint interview

    Eight practical lessons from Sam Altman and John Collison on code scans, agent teams, budgets, and prices customers can predict.

Thursday, 29 October 2026

  • Jim Nielsen’s BlogMore Front-end Bloggersread at source

    Celebrating SIM Cards

    It’s time to celebrate a little win. The other day, my mom contacted me saying her 10-year-old iPhone wouldn’t turn on. After getting a hold of the device and doing some family IT support, I concluded the battery was dead. So I bought her a new (old) one on Walmart (SE 3rd gen., if you must know). Her old phone used a SIM card, so I was expecting the process to go something like this: Take the SIM out of the old phone Put it in the new phone Setup the device Troubleshoot why there was no service Call my Mom’s carrier and work through the issue But step 4 and 5 never happened. The new phone “just” connected. I called her number. I texted it. Everything worked as expected. Everything worked as expected. Everything worked as expected. I didn’t have to Google a single question. I was floored. Flabbergasted. I know I shouldn’t have been because that’s how SIM cards are supposed to work, right? Like that’s the whole promise of a SIM card: you can seamlessly swap them between phones. And in this case, the tech worked exactly as promised. As I write this, I’m kind of amazed at how amazed I am that everything “just worked”. Shout out to anyone who has ever worked on SIM card technology. More things like this please :) Reply via: Email · Mastodon · Bluesky

  • Flavio CopesMore Front-end Bloggersread at source

    When one product pays another

    Stripe Pay sends money between businesses by a profile handle. An agent can prepare the transfer. A person still approves the exact amount.

  • Jeffrey Zeldman PresentsMore Front-end Bloggers6 min read

    The Day the Focus Died

    If we failed to do this, I feared, we would stop leading the industry and turn into “merely the CSS trick of the week.” The post The Day the Focus Died appeared first on Jeffrey Zeldman Presents .

  • Flavio CopesMore Front-end Bloggersread at source

    Pi Durable, Cloudflare Workflows, or Vercel Workflow?

    Compare agent crash recovery with durable workflow platforms. Follow one research task through storage, retries, approvals, and the work you still own.

  • Flavio CopesMore Front-end Bloggersread at source

    How to customize Cloudflare Access pages

    Customize Cloudflare Access login, denial, and CLI pages with HTML and Liquid, and tell a blocked visitor what to do next.

  • PiccalilliMore Front-end Bloggersread at source

    If we stop, we lose

    It's been a rather morale draining era in the making websites industry since the wider tech industry decided to gamble everything on LLMs. We at Piccalilli see it amongst the community and feel it ourselves. You'll also have noticed the velocity of posts has slowed down somewhat on this website with no new courses announced either. There's a couple of reasons for that. First, the numbers have taken a dramatic tumble — industry-wide — but also, aside from being very busy in the studio , we've been tired . Swimming against this particular current will do that, even for folks like us that have always operated like that. Something else you might have noticed is that a lot of other educators have gone a lot quieter this year too. I'm writing this post today to hopefully try and fix that. A shot in the arm I had a delightful conversation with CSS-Tricks head honcho, Geoff , yesterday. Aside from the excellent vibes as a result of CSS-Tricks being back as an independent publisher , I started in a rather glum mood. After spending a few minutes listening to Geoff's exciting plans though I really perked up. We're nowhere near CSS-Tricks here, but we've always looked up to them as an example of what years and years at the top of your game looks like. Sure, the DigitalOcean acquisition didn't work out, but the fact that the publication is not only back, but well up for the fight against the supposed death of web education is really inspiring to me. I needed that win, as did many others . I needed it so much, it's spurred me on to write this article to hopefully give us all a shot in the arm. There is no inevitable future and education will always matter A comment I see all the time is "we don't need articles and courses because we can just ask an LLM now", which I guess is true, but I could also eat an entire can of spray cheese. It ain't gonna nourish me! AI technologies have given anyone the ability to bring their ideas to life, but to produce a high quality end product that actually works for the people it needs to work for requires experience, specialist skills and creativity. That is a reality, which aside from Silicon Valley's best efforts, is why there are still working developers out there, regardless of "frontier model" power. Human developer's experience is necessary because LLM outputs still (somehow, after hundreds of billions of investment) fall short. Let me repeat that: their experience is necessary . Who inevitably contributed to that experience? Yep: educators. Let's get to work then This article is mainly addressed to fellow educators, but also to people that write on their personal blogs. You must keep going because people still need us . If we don't, we lose. The LLM era is opening up an enormous skills gap that's only going to get wider as the industry continues to pull up the ladder, eliminating entry level positions. We're needed to help people really understand how all of this stuff works , so even if they are at the behest of LLM mandates , they can produce better outputs. The technology is going nowhere — that toothpaste is long out of the tube — but how many other hype cycles have underwhelmed in the end? Spoiler, all of them The economics of the AI industry simply do not work and the technology — albeit ever-present in development — will fall into its actual place eventually, as a niche tool . With all of this in mind, we're fighting back too, so I'm opening up the guest authoring on this site again , just like Geoff is over on CSS-Tricks . I'm determined to get this website cooking again and I would love to share your words with the rest of the industry. Let's buck up our ideas and get cracking, everyone. There's lots to teach and I know we've got plenty of fight left in us. To quote our very own Mat Marquis : You and me, we’re not done until we say we’re done Don't let the bastards grind you down.

  • Flavio CopesMore Front-end Bloggersread at source

    How to use TinyFish

    Learn TinyFish with JavaScript: search the web, extract data, automate browser tasks, reuse logins, research topics, and monitor websites.

  • Flavio CopesMore Front-end Bloggersread at source

    The best macOS browsers for AI agents, and how to use them

    Choose a macOS browser for AI agents: compare Chrome, Safari, and Firefox, then set up browser control and test a complete local example.

  • Perishable PressMore Front-end Bloggers1 min read

    9G Firewall

    Hello! Just a quick post to let you know that the 9th version of my nG Firewall is in development. The 9G Firewall is not yet public, so if you encounter anyone claiming otherwise, they are incorrect. Unfortunately it is necessary to post this information because someone actually hijacked the name “9G Firewall” for their own project. So when people are looking for the next generation “9G” firewall, they are likely to find the counterfeit and possible confusion. Summary: 9G […]

  • Frontend Masters BlogMore Front-end Bloggers10 min read

    Useful @custom-media Presets

    Custom media queries let you name and reuse media queries the way custom properties do for values. Here’s a set of drop-in @custom-media presets for input mechanisms, breakpoints, and true HDR, plus a container style query version of each that works in every browser today.

Wednesday, 28 October 2026

  • Flavio CopesMore Front-end Bloggersread at source

    Give coding agents checks they can learn from

    Clear boundaries and enforceable checks make an agent's mistakes easier to find. Keep their limits visible, and inspect changes to the checks themselves.

  • David BushellMore Front-end Bloggers8 min read

    Danse Macabre

    My recent detour into Japanese detective fiction and the captivating mysteries of locked-room whodunits reminded me of popular BBC series Jonathan Creek. The show ran for three seasons between 1997–99. It returned with season 4 and 5 in 2003 and 2014 respectively. […]

  • Frontend Masters BlogMore Front-end Bloggersread at source

    How I Used Claude Code to Speed Up My Shell Startup by 95%

    I like the idea of "Please suggest 10 improvements to my ~/.zshrc" as a prompt (John Lindquist). Nick Taylor wrote up all the stuff it found for him and got nearly a second back for every fresh terminal opened.

Tuesday, 27 October 2026

  • DXDMore Front-end Bloggersread at source

    Processo de desenho do Não é Só um Logótipo

    O processo de desenho da identidade visual do "Não é Só um Logótipo" foi uma mistura entre planeamento, pesquisa e experimentação. O conteúdo Processo de desenho do Não é Só um Logótipo aparece primeiro em DXD .

  • Remote SynthesisMore Front-end Bloggersread at source

    Your Agent Just Deleted Prod (Web Unleashed Slide Deck)

    Just a quick post to share the slide deck from my presentation today at Web Unleashed in Toronto

  • Frontend Masters BlogMore Front-end Bloggers12 min read

    What should you put on a dynamic custom social media card image?

    There is technology to dynamically create custom social media cards (like this one!) — but what you put on it really depends.

Sunday, 25 October 2026

  • Jim Nielsen’s BlogMore Front-end Bloggersread at source

    Why My Dad Didn’t Have a Cell Phone

    Here’s Dave Rupert writing about all those emails, texts, phone calls, etc. we’re getting these days: Once upon a time it had utility, now it’s all noise and grifter slop demanding our attention and giving us to-dos That last part really hit: “giving us to-dos”. I feel this. So many of the messenger apps on my phone are other people laying claim to my time and attention. It reminds me of an interaction I had with my Dad years ago. This was back when cell phones were starting to become ubiquitous. Not smartphones , mind you. Cell phones, i.e. telephones that were mobile. Texting wasn’t really a thing yet. These were devices for making voice calls wherever you went. As a teen, it seemed like everyone had one: my teachers, my friends, even my friends’ parents. But not my parents. They were “behind the times”. (Everyone was getting cell phones and we didn’t even have caller ID on our landline!) One night at family dinner I asked, “Dad, why don’t you have a cell phone?” His response? “Why would I want to allow other people to contact me whenever they want?” I still think about that. Reply via: Email · Mastodon · Bluesky

  • Stéphanie WalterMore Front-end Bloggersread at source

    Pixels of the Week – October 25, 2026

    This week we explore the “disability dongle” problem, ecommerce accessibility issues that get customers stuck, and the double-edged sword of AI-generated prototypes. Also, don’t miss some horror graphic novels for Halloween and a gaming database for parents!

  • Remote SynthesisMore Front-end Bloggersread at source

    The Joy of Programming

    Coding brought two kinds of fulfillment: creativity and problem-solving. AI has dramatically impacted both, to opposite effect.

Friday, 23 October 2026

  • Frontend Masters BlogMore Front-end Bloggersread at source

    The Vertical Codebase

    A nice app architecture thought by Dominik: The Vertical Codebase. When component architecture came along, many started co-locating HTML/CSS/JS for a component, and it felt right. What if you take that one step further and co-locate based on the site’s conceptual areas? For example, the “dashboard” would have all the hooks, types, queries, etc., related […]

  • Geoff GrahamMore Front-end Bloggersread at source

    I’ve never been as nervous to publish on CSS-Tricks since my first article in 2015.

  • Bruce Lawson's personal siteMore Front-end Bloggers8 min read

    On CMA’s proposed NFC access conduct requirement for Apple’s iOS

    (Last Updated on 26 October 2026) If the title of this post didn’t get your pulse quickening, you’re probably in a coma. Sorry if it’s a bit clickbaity. On Tuesday, the daring, dauntless and doughty defenders of digital diversity at the CMA, UK’s competition regulator, published their Proposed NFC access conduct requirement for Apple’s mobile […]

  • PiccalilliMore Front-end Bloggersread at source

    The Index: Issue #203

    Overgrown, when plants invade your abandoned tabs This is fun. All my hobbies are getting slopped up, and it’s exhausting Video game orientated, but I'm sure many of you will resonate with this. FreeMix The AT protocol strikes again! This could end up being a proper Soundcloud challenger. In fact, an improvement on Soundcloud. Building an atproto link aggregator Again, the AT protocol continues to empower people making useful stuff for themselves and everyone else. The story of Tupo, my new daily logic puzzle A great write up of a very good, new puzzle game. JavaScript, when is this? Here's one from the Piccalilli archives that you might have missed to wrap up this issue. P.S. this is a good website from personalsit.es . Sponsor message Has your organisation gone too deep with frameworks or [gasp] LLMs and feel like you're stuck? We're helping clients get away from that noise and instead, focusing their efforts and budgets on actually doing stuff that will help them reach their goals. We do all of that while running this publisher, Piccalilli too! Our availability opens up again in late 2026 into 2027, so check out what we're about. Maybe we can be the key that unlocks your success in 2027 onwards. Check out our work

Thursday, 22 October 2026

  • Frontend Masters BlogMore Front-end Bloggers10 min read

    Building an Isolated Preview for AI-Generated HTML

    An iframe with srcdoc feels like a safe place to render HTML a model wrote. It isn't. Three tests show how the preview can read your page, escape the frame, and phone home, and four layers of protection close each hole.

  • Bram.usMore Front-end Bloggers1 min read

    GTA.js, a reimplementation of the 1997 Grand Theft Auto engine in JavaScript and WebGL

    Here’s a little sideproject I’ve been spending my tokens on: https://gtajs.wtf/ It’s a reimplementation of the 1997 Grand Theft Auto engine in JavaScript and WebGL.

  • PiccalilliMore Front-end Bloggersread at source

    Native masonry layouts with CSS grid lanes

    Native masonry layouts have been a long time coming to CSS and after years of debate over how they should work and fit into the language, we finally have display: grid-lanes . If you want the full backstory on how we got here, Sunkanmi Fafowora has a great overview of the grid-lanes announcement over on CSS-Tricks. Here, I want to focus on the technical side of masonry, why it took so long to get right, and how display: grid-lanes works. How we got here Masonry has been a long-running CSS challenge. Back in 2017, Rachel Andrew opened a CSSWG issue about creating a native Pinterest-style layout. As Rachel noted back then, the closest native CSS got to this was multi-column layout (column-count), but that flows items top-to-bottom. Masonry needs to flow items across rows, tightly packing them into whatever column currently has the most available vertical space. That same year, Tab Atkins-Bittner shared a clever Grid hack to approximate the layout. It relied on knowing each item’s height in advance, making it less practical for dynamic content. .hacky-masonry { display: grid; grid: auto-flow dense 1px / repeat(3, 1fr); } /* Manually set each item's row span */ .item { grid-row: span 50; /* Matches the item's 50px height */ } As cool as this hack was, having to know the exact height of every item ahead of time wasn’t very practical, especially when you’re dealing with dynamic content, where heights can change. When I spoke with Tab Atkins-Bittner for my piece on the evolution of CSS Masonry , they put the broader challenge of designing CSS layouts this way: “Flexbox was the first of the modern layout algorithms; we made a lot of mistakes and missteps while writing it, because we were trying to figure out how a modern layout model should work.” That same process of figuring things out played a role in masonry's development and until CSS had a better answer, many of us ended up reaching for David DeSandro’s legendary Masonry.js library instead. But the challenge wasn't just figuring out how to make masonry work in CSS. There was also the question of how it should fit into the language. Should it be part of Flexbox, an extension of Grid, or its own display value? For years, the CSS Working Group went back and forth without settling on a final syntax. Mozilla first explored adding masonry to Grid, and WebKit later picked up that approach. It lets you keep display: grid and use a special value for the tracks to enable masonry. .masonry { display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); grid-template-rows: masonry; } This kept Grid's familiar column definitions while letting the browser pack items vertically instead of aligning them into rows. You can read more about WebKit's reasoning in Help us choose the final syntax for Masonry in CSS . Google's Chromium team had a different take. They argued that masonry's layout algorithm was different enough from Grid to deserve its own layout mode, proposed as display: masonry . .masonry { display: masonry; masonry-template-tracks: repeat(auto-fill, minmax(14rem, 1fr)); gap: 1rem; } Their reasoning, along with an alternative syntax, is explained in An alternative proposal for CSS masonry . The debate continued through several rounds of proposals, including WebKit's broader item-flow idea for unifying aspects of Grid and Flexbox, but that approach was eventually dropped in favor of a simpler direction. In January 2025, the CSS Working Group agreed to reuse CSS Grid's track-definition and placement properties for masonry. By December 2025, the group had settled on a name for the new layout mode, grid-lanes . WebKit announced the direction in Introducing CSS Grid Lanes . How grid lanes works The nice thing about display: grid-lanes is that you don't have to figure out where every item goes yourself. You define the tracks along one axis, just as you would with regular CSS Grid and the browser handles placement along the other. For a typical masonry layout, that means defining your columns with grid-template-columns and letting the browser stack items into whichever lane makes the most sense. You still get familiar Grid properties like grid-template-columns , repeat() , minmax() , gap , and explicit placement. Under the hood, though, Grid Lanes uses a different layout algorithm: it maintains tracks along the grid axis and packs items along the stacking axis. That makes it possible to build responsive masonry layouts without calculating item heights yourself. A Basic Masonry Layout .masonry { display: grid-lanes; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: 1rem; } This defines as many columns as fit, with each column at least 14rem wide. The browser handles the rest, placing items into lanes as it lays them out. Unlike regular Grid, items don't need to share row heights, so each lane can grow independently. Here’s how this layout would look: The fill algorithm Unlike regular CSS Grid, Grid Lanes doesn't try to line everything up in rows. Instead, the browser keeps track of how much space each lane takes up and uses that to decide where the next item should go. The process is pretty simple: Check how much each lane is filled. Place the next item in a suitable lane, usually the shortest one. Update that lane's position and repeat. For example, with three columns, the first three cards go into separate lanes. If column 2 is now the shortest, the next card goes there. .masonry { display: grid-lanes; grid-template-columns: repeat(3, 1fr); gap: 1rem; } Controlling item placement Most of the time, you'll let the browser handle placement. But you can still use familiar Grid properties when you want more control. For example, grid-column: span 2 lets an item span two columns instead of occupying just one. .featured-item { grid-column: span 2; } The browser actually places these explicitly positioned and spanning items first , before it runs the masonry algorithm for the rest of the auto-placed items. Spanning items affects how the remaining space is distributed, so placement can get more complicated than simply choosing the shortest lane, especially in larger layouts with lots of moving pieces. Since items can appear in a different visual order from their source order, it's also worth checking that the layout still makes sense when read from the HTML. This matters for accessibility, too, as screen readers generally follow the document order rather than the visual layout. We’ll cover this in more detail later. A note on fit-tolerance The Grid Lanes spec is still evolving, but its direction is becoming clearer. The CSS Working Group dropped the broader item-* proposal for unifying flow controls across layout modes and settled on display: grid-lanes for masonry. Another change is the rename of flow-tolerance to fit-tolerance , a property that helps control how the browser chooses between lanes of similar heights. Say you have two lanes; one is 400px tall and the other is 398px . The second lane is technically shorter, but only by 2px . With a tolerance of 1em , the browser can treat both lanes as close enough in height and choose the lane that better preserves the source order, rather than always picking the shortest one. This can help prevent items from jumping ahead of earlier items just to fill tiny gaps. Here’s how different values affect the layout: .masonry { fit-tolerance: 0; /* favor the shortest lane */ } .masonry { fit-tolerance: 1em; /* Treat lanes within 1em as close enough */ } .masonry { fit-tolerance: infinite; /* Prioritize source order over compact packing */ } A value of 0 favors tighter packing, while a larger tolerance gives the browser more flexibility to keep items closer to their source order. infinite prioritizes source order, even if that leaves more empty space in the layout. The default is normal , which resolves to 1em. FYI infinite prioritizes source order, but it won’t guarantee it in every case. Similarly, 0 removes the tolerance for treating lanes of similar heights as equivalent. Switching directions Masonry doesn't have to flow vertically. With Grid Lanes, the tracks you define also determine the direction items are packed in. When you define grid-template-columns , items are packed vertically into columns. When you define grid-template-rows , items are packed horizontally into rows. The first is the familiar Pinterest-style layout, while the second creates a brick-like arrangement. Check out this Waterfall and Brick demo , by ICS Creative, to switch between the two layouts and see the difference. Both use display: grid-lanes , just with different track definitions. The WebKit team has also published the Field Guide to Grid Lanes . It includes an interactive playground, a reference for the different properties and values, and six demos covering layouts like photo galleries, recipe cards, timelines, and pinboards. Subgrids in masonry layouts One of the arguments for keeping masonry part of CSS Grid was that it would preserve features like subgrid . If masonry had its own display: masonry layout mode, getting nested elements to align with their parent's grid tracks could have required changes across multiple CSS specifications. Keeping masonry within the Grid model means subgrid can work alongside it. Say you're building a masonry layout of recipe cards, each with a title, an image, and a list of ingredients. subgrid lets the cards use their parent's grid tracks rather than defining their own, making it easier to align their internal elements. .masonry-container { display: grid-lanes; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } .recipe-card { display: grid; /* The card's internal columns align with the parent masonry grid */ grid-template-columns: subgrid; } Where we’re at today Grid Lanes has come a long way from the early proposals and workarounds, but there's still work to do. The specification is an Editor’s Draft, which means details can change as the CSS Working Group continues to refine the layout model. Browser support is another thing to keep an eye on. As of writing this article, Grid Lanes works in Safari 26.4 and later, but support in other browsers is still evolving. Check Can I Use for the latest updates, and consider using a simpler fallback for browsers that don't support it. Wrapping up Grid Lanes has come a long way from the early proposals and workarounds. Here's a quick recap of where things stand now: Masonry uses display: grid-lanes as a separate layout mode. Lanes are defined by grid-template-columns or grid-template-rows . Items are automatically placed into lanes based on available space. fit-tolerance controls how much difference between lanes is treated as a tie. The DOM source order stays intact, even when the visual order differs. Unsupported browsers can use a simpler fallback layout.

Wednesday, 21 October 2026

  • Jim Nielsen’s BlogMore Front-end Bloggersread at source

    No Need for Retirement When Utopia Is Around the Corner

    I’ve mentioned before my interest in the history and development of nuclear weapons . Currently, I’m reading The Doomsday Machine: Confessions of a Nuclear War Planner by Daniel Ellsberg (of Pentagon Papers renown). In the first chapter, Ellsberg talks about his time working at the RAND Corporation during the missile gap years when the U.S. thought it was falling behind the Soviet Union in nuclear capabilities. Many of his descriptions sound strikingly similar to the rhetoric coming out of places like Anthropic. For example, note the religious overtones of working at a corporation: I loved RAND, where I ended up spending ten years [...] Much, I imagined, like members of a religious order would, I shared with my colleagues a sense of brotherhood, living and working with others for a transcendent cause. They were insiders : burdened with the responsibility of knowledge others did not possess. precisely in my early missile-gap years at RAND and as a consultant in Washington, there was our sense of mission, the burden of believing we knew more about the dangers ahead, and what might be done about them, than did the generals in the Pentagon or SAC, or Congress or the public, or even the president. It was an enlivening burden. And what was their “enlivening burden”? Saving the world: [My colleagues] shared a feeling—soon transmitted to me—that we were in the most literal sense working to save the world. What really stood out was this part, where Ellsberg describes how he and his colleagues truly believed the end was nigh: From the Air Force intelligence estimates I was newly privy to, and the dark view of the Soviets, which my colleagues shared with the whole national security community, I couldn't believe that the world would long escape nuclear holocaust. Alain Enthoven and I were the youngest members of the department. Neither of us joined the extremely generous retirement plan RAND offered. Neither of us believed, in our late twenties, we had a chance of collecting on it. This reminds me of the report that AI researchers have taken up smoking as a way to signal their belief that AI will cure cancer before smoking kills them. At this point, I wouldn’t be surprised to hear a lab like Anthropic announce they’re discontinuing all employer-sponsored retirement benefits. It’d be a small sacrifice on behalf of the employees to demonstrate their faith that universal high income is just around the corner. (The corporate cost savings would just be a nice bonus.) Reply via: Email · Mastodon · Bluesky

  • Robin WieruchMore Front-end Bloggersread at source

    Testing AI-Generated Code: Lint the Pattern, Test the Decision

    Testing AI-generated code without the noise: lint the patterns coding agents follow, share one test harness, and add tests only where a file leaves its pattern.

Tuesday, 20 October 2026

  • Ben FrainMore Front-end Bloggersread at source

    Colour variants from base colours with OKLCH, CSS relative color, and CSS functions

    Many others have covered the manipulation of colour in CSS. This is me documenting what has worked for me, practically, 'in the wild'. It is a common requirement to need a variant of an existing colour. Think about the borders for a visual pod/component; it may have a background colour but you need some variant […]

  • Frontend Masters BlogMore Front-end Bloggersread at source

    “I Redesigned VLC After 25 Years”

    I watched this whole video by Juxtaposed, assuming it was a real redesign of the VLC player, but alas, it is not official. Nevertheless, it should be, and it’s a wonderful example of how much real human brainpower it takes to design something well.

  • David BushellMore Front-end Bloggers2 min read

    How not to migrate from Cloudflare DNS

    So you’ve been shamefully using US Big Tech giant Clownflare for DNS? It’s time to find an inopportune time to migrate away to a “European alternative” . You absolute must not follow these steps on a busy weekend when you must leave for hours on short notice. […]

  • Josh Comeau's blogMore Front-end Bloggersread at source

    The Future of CSS ✨

    Every year, browser vendors collaborate via the Interop project to synchronize their efforts on new HTML/CSS/JS features. This year, there’s a ton of super exciting features being considered! In this blog post, we’ll explore the CSS of the future, to get a glimpse of what we’ll soon be able to do.

  • Jeffrey Zeldman PresentsMore Front-end Bloggersread at source

    Figma Tips and Shortcuts

    ℅ Automattic Design: The post Figma Tips and Shortcuts appeared first on Jeffrey Zeldman Presents .

Monday, 19 October 2026

  • Jim Nielsen’s BlogMore Front-end Bloggersread at source

    No More Icons In Every Menu By Default

    Have you heard the good news? I bemoaned the approach of putting an icon in every menu item by default which shipped with macOS Tahoe — but now it’s gone in Golden Gate! John Gruber wrote about this reversion back in June , including the fact that Apple’s new Human Interface Guidelines specifically call out Tahoe’s approach to menus as an example of what not to do on macOS. As the old saying goes, it takes a big man corporation to admit when they’re wrong. As I mentioned in my original post , one of the arguments I had in my quiver against this practice was “Apple doesn’t do it”. But once Apple started putting icons in all their menus in Tahoe, I lost a persuasive point in my argument. But now, I think I have an argument that’s even stronger than before! It’s no longer: “Apple doesn’t put icons in their menus.” It’s: “Apple tried putting icons in all their menus, and even they went back on it!” They designed it, shipped it, lived with it for a year, then publicly changed their guidance on it. To me, that’s a lot more persuasive than simply saying, “Apple doesn’t do this.” Choosing not to do something you’ve never done is one thing. Choosing not to do something you’ve done is experience . That’s the essence of life: learning by doing . Reply via: Email · Mastodon · Bluesky

  • Jeffrey Zeldman PresentsMore Front-end Bloggersread at source

    Now Playing: “Side Two”

    For your listening pleasure: 17 new tracks of instrumental music pulling from jazz-funk, Italian movie soundtracks, electronica, hip-hop, art rock and beyond. The post Now Playing: “Side Two” appeared first on Jeffrey Zeldman Presents .

  • Frontend Masters BlogMore Front-end Bloggers8 min read

    Structured Output with TanStack AI

    Part 2 of this intro to TanStack AI covers structured output: constraining the model's response to a Zod schema, then streaming that JSON in and rendering it while it's still incomplete.

Sunday, 18 October 2026

  • Stéphanie WalterMore Front-end Bloggersread at source

    Pixels of the Week – October 18, 2026

    This edition explores agentic commerce interfaces beyond chat UIs. Don't miss a fun clock made from trash, a webcam theremin experiment, cool dataviz and tool to know if a book chapter will make you sad.

  • localghostMore Front-end Bloggers6 min read

    Digital recipe management for fastidious cooks

    Much like your favourite recipe websites, I'm not going to get straight to the point, I'm going to start with a backstory and you're not getting a skip link. Having grown up with a dad who read cookbooks for leisure, and who caused me to turn vegetarian for several weeks once at…

Saturday, 17 October 2026

  • Swizec TellerMore Front-end Bloggersread at source

    No more tech debt

    For the first time in my career we _completed_ a design system migration. The new math on big rewrites tickles my soul.

Friday, 16 October 2026

  • David BushellMore Front-end Bloggers3 min read

    Cloudflare killed Deno and look I’m on TV!

    ““Didn’t you already say goodbye to Deno? Get new material!””I know, I know, but not even a week after declaring my friendship over with Deno they actually killed Deno! The runtime is going away, and sorry call me pessimistic, but I highly doubt a community fork of any value will survive for long. […]

  • Bruce Lawson's personal siteMore Front-end Bloggers2 min read

    Reading List 362

    Yikes, once again it’s been ages since I posted a reading list, as I’ve been shuttling between Brussels, London and Lawson Towers a lot. This reading list is courtesy of Vivaldi browser, who pay me decent money to fight for a better web and don’t moan at me for reading all this stuff. We’ve just […]

  • Frontend Masters BlogMore Front-end Bloggers10 min read

    Unlocking AI in Your Apps with TanStack AI

    TanStack AI is a strongly typed set of libraries for adding AI features to your apps. Part 1 of this intro covers basic setup and prompting, streaming responses, persisting threads to your database, and resuming a response after a mid-stream refresh.

  • PiccalilliMore Front-end Bloggersread at source

    The Index: Issue #202

    Tiny Little Office This is really smart. It's a word processor, along with other common office software like spreadsheets, but it's completely URL powered. Introducing the Accessible Components Library You could not be in better hands than with TetraLogical and they've produced a really good collection of common components, all with thorough documentation, accessibility requirements and testing scenarios. we were online Something we've certainly noticed about this particular morale-draining era is there seems to be a real drive to create websites centered around a shared human experience and long may it continue. What 10,000 home pages put in their head So much about web performance is linked to what's in your which this article (and very useful looking tool) breaks down well. Study explores how AI use affects performance on math and reasoning tasks A worrying read for fans of healthy cognition. A handful of reasons JavaScript won’t be available Here's one from the Piccalilli archives that you might have missed to wrap up this issue. P.S. this is a good website from personalsit.es . Sponsor message There's been a drive to ship ship ship in this AI era but increasingly that means a lot of volume and very little substance. At Set Studio, we move incredibly fast because we center everything around a solid strategy and work with the amazing capabilities that modern browsers give us, underpinned by progressive enhancement, to make sure every user gets a high quality equitable and accessible experience. We're also the agency behind The Index and Piccalilli because we think it's important to share this way of working with the wider community. With availability opening up in 2027, we're the agency you can actually trust to do right by you and your user base. Reach out to us for a chat and let us show you how. Check out our work

  • Frontend Masters BlogMore Front-end Bloggers3 min read

    SVG “Linked Parameters” Will Change How We Do Icon Systems

    Maybe we can get back to an img-based icon system?

Thursday, 15 October 2026

  • Jim Nielsen’s BlogMore Front-end Bloggersread at source

    We Need All the Disciplines

    From where I sit, figuring out what to build, building it, and shipping it are all part of the art of making software. Many disciplines have emerged through the years to facilitate this work: product, design, engineering, devops, etc. We need all these disciplines to make great, dependable software (granted, in different doses). Each brings different values and judgments; each sees things the others don’t. And including all might mean going a bit slower. Human collaboration may seem less “efficient” than handing the work over entirely to the machines. But inefficiency may be the cost of collaborating with humans, rather than extracting an output from a machine. We gain not only from their judgment and expertise in a particular discipline, but from the relationship, trust, and shared understanding that blossoms from making something together. As the old proverb says: “If you want to go fast, go alone. If you want to go far, go together.” Reformulated for today: If you want to go fast, go with the LLM. If you want to go far, go with your fellow humans. Reply via: Email · Mastodon · Bluesky

  • Jeffrey Zeldman PresentsMore Front-end Bloggers1 min read

    Silly Old Bear

    Remembrance of Poohs past. The post Silly Old Bear appeared first on Jeffrey Zeldman Presents .

  • Ahmad ShadeedMore Front-end Bloggersread at source

    Fit height to background pattern size with calc-size()

  • Ana RodriguesMore Front-end Bloggersread at source

    Goodbye sweet Jessie

    This post has a content note of pet loss. Visit the link directly if you're okay with reading it.

Wednesday, 14 October 2026

  • Thoughts From EricMore Front-end Bloggers6 min read

    My Interop 2027 Rankings

    In which I explore why I ranked what I did for Interop 2027.

  • Bram.usMore Front-end Bloggers4 min read

    Scroll-Triggered Animations Debugger (DevTools Extension)

    I’m extremely pleased to announce the release of Scroll-Triggered Animations Debugger , a DevTools extension to visualize and debug CSS Scroll-Triggered Animations .

  • Bruce Lawson's personal siteMore Front-end Bloggersread at source

    Farage believes Andrew Tate is “an important voice”

    Now we know that the execrable Andrew Tate is wanted by British police for allegedly making indecent images of a child, rape, stranging women during sex, and possession of extreme pornography depicting sexual intercourse between people and live animals — one involving an eel and another involving a horse. Let us not forget that Nigel […]

Tuesday, 13 October 2026

  • Bram.usMore Front-end Bloggers5 min read

    Introducing css-typed-om, a complete and WPT-tested polyfill for CSS Typed OM

    Being a big fan of the CSS Typed OM , I’ve wanted a proper polyfill for it for years. Just before my summer vacation back in July, with the help of Gemini/Antigravity, I finally built one: css-typed-om .

Monday, 12 October 2026

  • Jim Nielsen’s BlogMore Front-end Bloggersread at source

    The Dock on Mac, From OS 10 to macOS 27

    I wrote the chapter on app icon history for The iOS App Icon Book . The other day I found an old note stashed away where I had started researching the macOS version of that chapter (which Michael ultimately ended up writing). At the time, I didn’t know what to write. I mean, how do you write a history of icon design for the Mac? It’s rich! To get my creative juices flowing, I started by researching the different docks in macOS through the years and compiled them all into a single graphic (big shout out to this compilation of images on 512 Pixels ). I just wanted to preserve and archive that image. Check out the high-res version here . That’s it, that’s the post. Reply via: Email · Mastodon · Bluesky

  • Bruce Lawson's personal siteMore Front-end Bloggers2 min read

    EU, EU, It’s off to work we go

    Last week, I had an exciting few days in Brussels, meeting with the European Commission with other browser vendors, technology groups, and representatives of a Big Tech Gatekeeper about the latter’s sustained and relentless malicious compliance with the Digital Markets Act, the EU’s law “to make the markets in the digital sector fairer and more […]

Sunday, 11 October 2026

  • Jim Nielsen’s BlogMore Front-end Bloggersread at source

    The Fascinating World of Domains

    Pete Millspaugh has a lovely article over on WIRED that peers into the world of domains. (If you’re as interested in the esoteric details of domains as I am, follow Pete’s writing at Dot Com Press .) You should just read the article, but here are a few things that stood out to me. The .com Registry Did you know who the registry for .com is? I didn’t. The registry that owns .com, Verisign, makes a billion and a half dollars every year just by keeping the lights on. To Verisign’s credit, the lights never go out: It reports 100 percent uptime over the past 28 years. It’s a pretty slick business model, watching over a database of words and collecting annual renewal fees. Warren Buffett thought so too, investing in Verisign in 2012, when its stock price was about one-eighth what it is today. Why is it simultaneously surprising and not surprising that the company running .com makes billions and has 100% uptime over almost three decades? Maybe GitHub should reach out for some advice, lol. Buying Domains Is a Spy Thriller Apparently the last time you could buy generic top-level domains (gTLDs) was in 2012. So now that ICANN is providing another window of purchases in 2026 — and nobody knows when another window will open — there’s a lot of interest in capitalizing on these moments for new gTLDs. most organizations [are] extremely secretive about their plans. One applicant from the last round tells me companies were flying around the world, meeting in person to avoid any risk of digital leaks, avoiding Gmail for fear of Google spying. Instead of email or video calls, she flew to London, then to Madrid. “We did it all in person. People got a little weird and scary, super paranoid.” There’s a certain irony to this — people flying around the world to conduct business on owning a piece of the internet because they don’t trust the internet. It appears the future of the internet is to be negotiated offline lol. More Domains = More Online Handles We haven’t had new gTLDs since 2012. Why do we need more? I can imagine a future where expressive top-level domains become our personal brands, identities on the internet. This is already true in some nerdy corners of the web, like on Bluesky, where your domain is your username. I don’t call my internet friends Neal and Luke, I call them neal.fun and luke.zip. Instead of joining the land rush to grab our username on each new social media site, we’ll carry our domain around the web with us. I’m telling you, domains are the OG handles on the internet . More domains mean more opportunities for individual expression at the root layer of internet infrastructure — that makes sense for a web that’s meant to be worldwide! You Think You Have a Domain Vice? As developers, we often joke about our addiction to buying domain names for our side projects. But buying a domain name — e.g. my-side-project.com — is child’s play compared to buying a generic top-level domain name (gTLD). That’s where the domain whales are. ICANN charges a $227,000 application fee for each string, to recover the cost of running the program. The $36 million or so that Nova will need to cover those fees […] is coming from the personal bank account of Yoni Belousov, a reclusive domain investor (industry jargon: “domainer”) who’s been in the business since he was 14 years old. Next time somebody asks me what I’d do with an insane amount of wealth, I now have the jargon for an answer: “I’d become a domainer.” A Few Fun Facts to Close A few things about domains I didn’t know until I read this: all two-letter extensions are off the table. Those belong to countries, like .co in Colombia and .me in Montenegro and .ai in Anguilla. If you want to run a geographic TLD, like .nyc or .paris, you need approval from that municipality your string can’t be too similar to an existing one (.corn is a no-go; looks too much like .com) certain special strings are off limits, like .icann and .www (wouldn’t that be a trip). www.www would be a baller domain! Just think of the recursion you could do with that on the subdomain level. Reply via: Email · Mastodon · Bluesky

  • Stéphanie WalterMore Front-end Bloggersread at source

    Pixels of the Week – October 11, 2026

    This week brings some resources on neurodiversity and cognitive accessibility, explains why design struggles to justify its value to business, and how AI exposes design’s craft crisis. Also don't miss some nice accessible color combinations and funny wildlife photos.

  • David BushellMore Front-end Bloggers4 min read

    D-Bus Hell

    The time has come to address the elephant in the comments. Whenever my blog hits a place with a comments section the most predictable comment I see — besides some variation of “this idiot is utterly delusional!”† — is this one: “lol I read the domain as “D-Bus Hell” Random commenter”I’d prefer if […]

Saturday, 10 October 2026

  • Zell LiewMore Front-end Bloggers2 min read

    Redefining My Relationship With You

    I no longer knew how to define my relationship with the people who read my work. Not teacher and student, not leads and customers. Here's where I eventually settled: fellow wayfarers.

Friday, 9 October 2026

  • Adrian RoselliMore Front-end Bloggers4 min read

    Decorative Images…

    …aren’t a thing. Three hand-drawn lines curling together like an S or three skinny snakes trying to spoon. At least not as far as people are concerned. Yes, this is an absolutist take, but sometimes it’s necessary to take the absolutist position to force someone to justify their own reasoning.…

  • Robin WieruchMore Front-end Bloggersread at source

    Toward a Self-Improving Agentic Code Review Loop

    An agentic code review loop where each developer fires their own AI review skill at pull requests, the author's agent answers, and a scorecard rates each skill.

Thursday, 8 October 2026

  • Bram.usMore Front-end Bloggers4 min read

    <​calc-input>, a custom input element that accepts mathematical formulas

    Continuing my streak of small form-related Custom Elements (like ) , I built . It’s a custom input element that accepts mathematical formulas — such as 2 + 3 or (2 + 3) * 4 — and automatically toggles between showing the formula on focus and the calculated result on blur.

  • Bram.usMore Front-end Bloggers2 min read

    caniname: CLI tool to check project name availability across Netlify and NPM (and other sources)

    Whenever I build a new tool or custom element (like or ), I always end up doing the same manual dance: checking if the package name is still free on NPM and if the matching .netlify.app subdomain is still unclaimed on Netlify. To automate that check, I built caniname .

  • Jim Nielsen’s BlogMore Front-end Bloggersread at source

    “Getting off the Modernization Treadmill”

    My notes from this talk by Alexander Petros at Big Sky DevCon 2026 . Alex starts by noting how “modernize” used to mean something along the lines of “update this thing that was made before I was born”. But now “modernize” means something more like “update this thing from 5-10 years ago” (hence the framing of the talk, the “modernization treadmill”). Using a real-world example of an incredibly slow website that was required to access state-sponsored programs for welfare, Alex points out the disparity in conditions between those of us who make software and those who have to use them: The people who develop these websites are usually doing so on high-powered internet connections and high-powered devices, but they're not using them in the conditions that the people who most need those benefits are going to be. Then he shows a Reddit thread where somebody essentially posted, “I’m having problems with this website. I’ve been waiting for months for my application to go through. Any suggestions?” And one Reddit user responded, “The best thing you can do is go into the physical office, get a case worker, and your problems will be solved within the hour.” The irony. I guess we've come full circle now. It used to be: “Don’t talk to anybody. It’s faster and more convenient to use the website!” But now it’s: “Don’t use the website. It’s faster and more convenient to talk to somebody!” Have we failed at making websites? And is our failure, at least in part, rooted in the fact that we don’t leverage the basic tools for making websites: HTML, CSS, and (in a distant third) JavaScript? Alex goes on to argue that the technologies of the web have an ideological bent and, if used as designed, can solve so many of the performance, accessibility, and usability issues that plague so many websites. The grain of the web’s technologies are rooted in these values: User-friendly Backwards- and forwards-compatibility Long-term viability Universal accessibility Which means if you use them as intended, they are optimized to deliver outcomes rooted in those same values. So if you like those values and you want those outcomes, use the platform. Take HTML, for example. Here’s Alex: HTML does [performance improvements] for you for free. If you've coded your website in a proper, semantical, structure HTML style, it will just get better over time at zero cost to the people who built that website HTML is your friend. HTML won’t give you up or let you down . HTML will make it difficult for you to make a bad website. Write it in to the requirements of the project you’re doing that it work without JavaScript. Not necessarily that it doesn’t have any JavaScript, but just that the core functionality of the website can happen without JavaScript. If you do this […] you will find that it’s very hard to deliver a bad web page because the structure that HTML requires is one that fundamentally is good for the user, performant, and cost effective. Technologies are imbued with culture, which influences what you do and how you do it. If you can align your ideological beliefs with your technological choices, you might end up with an outcome that aligns with your values — who would’ve thought, eh? A lot of modern software developers come from websites like Facebook, they come from big tech companies [who] fundamentally have a different set of priorities. Their job is to keep you on the website as long as possible so that you consume more ads. But that’s the opposite set of requirements and priorities that the government needs to be doing, which is to build something that is clean, quick, efficient, and gets you in and out as fast as possible. So [I tell people] that the technology they use comes from [an] ideological place. But there are different ideological places that produce different technological results and if we start from those through lines then we can produce services that help people who need them. The ideological principles of the web are well established : users over everything else. If you use HTML as much as possible, you’ll make something that’s as user-friendly as possible on the web. Reply via: Email · Mastodon · Bluesky

  • Kilian ValkhofMore Front-end Bloggers2 min read

    I’d like to have a universal pseudo selector in CSS

    Last week, I wasted about an hour of my time figuring out why a certain element had different dimensions than the same element elsewhere in the DOM. It had the same CSS and the same defined width and height, but it still rendered differently. Yes, it was box-sizing. Of course it was box-sizing. I immediately […] The post I’d like to have a universal pseudo selector in CSS first appeared on Kilian Valkhof .

  • Ana RodriguesMore Front-end Bloggers1 min read

    My Interop feature ranking

    The Firefox team just launched a website that allows users to rank the Interop 2027 proposals that they care about. And I care about things - for selfish reasons and for work. And that's a challenge. I want to rank things that only benefit me and my blog but I also want to rank…

  • Swizec TellerMore Front-end Bloggers1 min read

    When code is cheap, judgement becomes the job

    Software engineering has changed in the last 2 years. Here's how that looks without the fluff. Real company, big stakes, finite token budget

Wednesday, 7 October 2026

  • Bram.usMore Front-end Bloggers3 min read

    Bringing Microsoft Internet Explorer’s proprietary “Interpage Transitions” back to Modern Browsers using the View Transition API

    Back in late 2024, I started working on a fun end-of-year side project named ie-page-transitions . It”s a CSS + JS library that brings back Microsoft Internet Explorer’s proprietary “Interpage Transitions” to modern browsers, powered by the View Transition API. After sitting unfinished for a while, I finally got all 23 classic effects over the finish line and published the project on page-transitions.style .

  • David BushellMore Front-end Bloggers4 min read

    A sustainable web career, for when all this blows over

    For better or worse the web industry is going through a bit of a phase. The reasons are largely irrational. People still need the web, nothing has changed there. Regardless, the financials of this business are a struggle. Longterm career prospects are looking dicey. […]

  • Ana RodriguesMore Front-end Bloggers1 min read

    Bookmarks that were lingering in tabs

    I was a big girl this week and I finally read and closed all the tabs I had open. Here's my picks from that selection. Fresh browser start - here I go. Bookmarks related to tech and web development Native HTML and CSS Features That Replaced JavaScript by Ronalds Vilciņš. What…

Tuesday, 6 October 2026

  • Jim Nielsen’s BlogMore Front-end Bloggersread at source

    Apple’s App Icon HOA

    Louie Mantia has a great post about how app icons are converging towards the squircle on iOS and macOS. His post reads like a history. If you’re wondering, “How did we get to a place where all app icons are becoming squircles?” Mantia’s post answers that question by starting at the beginning. It’s hard to walk away from Mantia’s article without a sense of empathy for Apple’s position, like “Oh ok, I get why they’re doing what they’re doing. It makes sense.” Apple’s direction is kind of a tacit acknowledgement to how most people are shipping app icons. Apple is “paving the cowpaths” as it were, because most app icons are just brand logos. Nowadays, it’s these bland, big-business logo icons that make up a good chunk of iOS Home Screens and macOS Docks, instead of the beautiful, illustrative app icons that used to dominate our devices. So many app icons are just logos in a squircle, so Apple made tools like the Icon Composer and glass effects to help make that approach look good by default. Apple is helping most people most of the time make app icons that don’t suck. [Apple is making] it easier for all apps to fit in on the platform, especially apps built by designers and developers who aren’t familiar with how to make an icon that looks great next to first-party icons. The net effect is: some of the platform’s best icons look worse, while some of the platform’s worst icons look better. In other words, this new approach raises the floor but it also lowers the ceiling. The thought that came to mind as I read Mantia’s post was, “This reminds me of HOAs.” I grew up in a neighborhood where anyone could do anything with their homes and yards, so you had this eclectic mix throughout the neighborhood — everything from “Wow, that house is so unique!” to “That thing is a dump.” Somewhere along the way HOAs became more prevalent (in my neck of the woods), where all the houses in a neighborhood have to meet a certain standard — and so they all start to look the same. It keeps the dumpy things out, yet nobody stands out . That’s kinda what macOS feels like right now with regard to app icons. For better or worse, squircle app icons are Apple’s HOA and we’re all just living in it. Reply via: Email · Mastodon · Bluesky

Sunday, 4 October 2026

  • Jim Nielsen’s BlogMore Front-end Bloggersread at source

    “I’m Embarrassed on Behalf of the Tech Industry”

    That’s something Ben Thompson said a recent episode of Dithering . He was referring to how he felt while trying to help his mom get control of her digital life. Everything was just too hard and convoluted and he felt embarrassed as someone who works in tech. That very same evening, I randomly got this text from a family member. I hear this a lot from family and friends who sit outside tech. “Nothing works.” “Everything is hard to use.” “I can’t make sense of this.” And to them I am a representative, a connection, to this pain in their lives. And I, too, am embarrassed on behalf of the tech industry — by our collective failure. Reply via: Email · Mastodon · Bluesky Related posts linking here: (2026) “Getting off the Modernization Treadmill”

  • Stéphanie WalterMore Front-end Bloggersread at source

    Pixels of the Week – October 4, 2026

    👉🏻 Curated weekly UX Research, Design & Tech resources: building a general-purpose accessibility agent, how to make your design system AI-ready, WCAG 3.3.4 error prevention explained, why you got faster but your company didn't, the AI delegation matrix for your UI, flame painting art on copper, curated branding inspiration, how mechanical watches work, maps of book characters' journeys, free no-login utility tools.

Saturday, 3 October 2026

  • DXDMore Front-end Bloggersread at source

    Não é Só um Logótipo, literalmente

    A identidade visual do podcast "Não é Só um Logótipo" é um convite à descoberta de um sem fim de curiosidades sobre a disciplina do design. O conteúdo Não é Só um Logótipo, literalmente aparece primeiro em DXD .

  • Jeffrey Zeldman PresentsMore Front-end Bloggersread at source

    Another Saturday, Another Song.

    🎧 “Side Two” LP in progress. At 14 songs, it is nearly complete. I expect to release it before the year’s end. The post Another Saturday, Another Song. appeared first on Jeffrey Zeldman Presents .

  • David BushellMore Front-end Bloggers4 min read

    Friendship ended with Deno, now Node is my best friend

    It’s finally time I go crawling back to Node! I’ve been using Node heavily this month on a SvelteKit client project. When did Node get so good‽ Deno has been my go-to runtime for so long I forgot how to Node. Now I’m back, I find all the ECMAScript† sugar is supported and the old annoying APIs have […]

Friday, 2 October 2026

  • Hidde's blogMore Front-end Bloggers5 min read

    How IT can get more sustainable quicker: notes from Green IO

    At Green IO this week , I heard about offshore wind, sustainability data, and cloud certification. This post has some notes I took. They all in some way relate to what can get us to more sustainable IT quicker. Better sustainability data It's really hard to reason about your…

Wednesday, 30 September 2026

  • Andy BellMore Front-end Bloggersread at source

    In response to “The death of web development education”

    I read Mat​hia⁠s S​chäf⁠er’s excellent post, titled The death of web development education . I was thinking about how I can contribute to the conversation and really struggled to articulate the problem. The most effective way I can contribute, in my opinion, is a crude sketch I…

Sunday, 27 September 2026

  • HeydonWorksMore Front-end Bloggersread at source

    The AI Artist Paradox

    Whichever way you cut it, you cannot be an AI artist.

  • Julia EvansMore Front-end Bloggers5 min read

    Replacing the old battery on rechargeable bike lights

    Hello! Recently I needed bike lights for my bike. And I remembered that I already had rechargeable bike lights that I bought ten years ago, that I hadn’t tried in a long time. I tried to recharge them, but after fully charging them, they only worked for maybe 5 minutes before…

Thursday, 24 September 2026

  • text/plainMore Front-end Bloggers7 min read

    “The” IP Address

    As elaborated in a prior post, sites and services often try to use an IP address as an input into protection (e.g. blocking a spammer) or customization (providing local weather info) algorithms. Commonly, software would like to know “What is this device’s IP address?” Unfortunately, this is not a trivial question to answer, because it Continue reading "“The” IP Address"

  • The Web Witch's BlogMore Front-end Bloggers1 min read

    A Short Update on Designing for Foldable Devices

    And here we are three years after I wrote about the Google Pixel Fold being announced , followed now with the announcement of the iPhone Duo...(I have questions about the naming by the way). Four years ago I was talking about web primitives in the platform for the Surface Duo.…

Monday, 21 September 2026

  • Jonnie HallmanMore Front-end Bloggers16 min read

    Building the Open Standard website with Stripe

    Reuniting with my friends at Stripe, I collaborate with them on the landing page for Open Standard.

  • The Code BarbarianMore Front-end Bloggersread at source

    Faster SSE Responses with Async Generators and Promise.race()

  • Phil NashMore Front-end Bloggersread at source

    Build a contact form with Astro and Resend

    I try to keep my email address from appearing on public websites to avoid spam. But I do like people to be able to contact me if they have something I might be interested in. The solution for this? A contact form! This site is mostly statically generated, but as it is currently built with Astro and hosted on Cloudflare Workers , I can designate an endpoint as dynamic, use it to accept a form submission, validate the data on the server, and send it to my email inbox using Resend . In this post, I’ll show you how I built it. What it does When you visit /contact , the Astro framework renders an HTML page with a form on it containing three inputs: the user’s email address, a subject, and the message they want to send. When the user fills in the form and submits it, the browser makes a POST request to the same URL, and the server-side code kicks in. It extracts the details from the form, validates the data, and uses the Resend API to send a message to my email address. If the user didn’t include all the details, the page is rendered again with error messages and the existing content of the form so that they can correct the form and submit again. For full disclosure, I currently work at Resend, but I implemented the first version of this back in 2024 . It’s always nice when you go from a happy user of a service to working there. Let’s see how to build this. Start with the HTML Astro pages are simple to build; they start with the component script, which is effectively TypeScript frontmatter for your template, and finish with the component template, made up of HTML and other Astro components. I built my contact form as a page at the /contact route, so I started with a file at the src/pages/contact.astro path in my Astro app. The contact form then starts with the HTML: --- // Component script --- form method = "POST" > div > label for = "email" > Your email label > input type = "email" id = "email" name = "email" placeholder = "you@domain.com" required /> div > div > label for = "subject" > Subject label > input type = "text" id = "subject" name = "subject" placeholder = "Hi Phil!" required /> div > div > label for = "message" > Message label > textarea id = "message" name = "message" placeholder = "Your message" required > textarea > div > div > button type = "submit" > Send button > div > form > Setting the form’s method to "POST" but not providing an action means that it will submit to the same route that rendered it. My site is set to output as a static site, but you can enable on-demand dynamic routes and rather than prerender a static page, it will dynamically render pages and respond to POST requests. To do this, just add the following to the component script: --- export const prerender = false ; --- If your Astro site is set to server mode , this isn’t required. Set up your secrets To send emails with Resend you will need a Resend account , a domain verified with Resend , and an API key . With those sorted, add the API key, an email address you’ll be using to send the email using the verified domain, and the email address you’re sending it to (yours), to the .env file: RESEND_API_KEY = RESEND_TO_EMAIL = RESEND_FROM_EMAIL = You can then load and validate these variables in Astro config in astro.config.mjs . // astro.config.mjs import { defineConfig , envField } from "astro/config" ; export default defineConfig ({ env: { schema: { RESEND_API_KEY: envField . string ({ context: "server" , access: "secret" }), RESEND_TO_EMAIL: envField . string ({ context: "server" , access: "secret" }), RESEND_FROM_EMAIL: envField . string ({ context: "server" , access: "secret" , }), }, validateSecrets: true , }, }); This is incredibly useful as this config both validates that the environment variables are present when you build or run the application and ensures that the server-side secrets aren’t included in any bundled artifacts. Return to the src/pages/contact.astro page. You can now import those environment variables from astro/env:server . Another bonus is that they will be correctly typed. --- export const prerender = false ; import { RESEND_API_KEY , RESEND_TO_EMAIL , RESEND_FROM_EMAIL } from "astro:env/server" --- Prepare values and errors For both GET and POST requests, the page renders the current field values in the HTML. It may also need to render validation errors or a success message. Let’s set those up in contact.astro . --- type ContactErrors = { email ?: string [] | undefined ; subject ?: string [] | undefined ; message ?: string [] | undefined ; }; let errors : ContactErrors = {}; let email = "" , subject = "" , message = "" , successMessage = "" ; --- The page can be updated to show the success message if it is present or the form and any values or errors. --- // Component script --- { successMessage ? ( p > { successMessage } p > ) : ( form method = "POST" > div > label for = "email" > Your email label > { errors . email && errors . email . map (( error ) => ( p class = "form-error" > { error } p > )) } input value = { email } type = "email" id = "email" name = "email" placeholder = "you@domain.com" required /> div > div > label for = "subject" > Subject label > { errors . subject && errors . subject . map (( error ) => ( p class = "form-error" > { error } p > )) } input value = { subject } type = "text" id = "subject" name = "subject" placeholder = "Hi Phil!" required /> div > div > label for = "message" > Message label > { errors . message && errors . message . map (( error ) => ( p class = "form-error" > { error } p > )) } textarea id = "message" name = "message" placeholder = "Your message" required > { message } textarea > div > div > button type = "submit" > Send button > div > form > ) } Verify the input Next, we need to validate the submitted data. I chose to do this with zod , since it is already installed as part of Astro. Start by importing zod and defining two schemas. --- import { z } from "astro/zod" ; const normalizedFormSchema = z . object ({ email: z . string (). trim (). catch ( "" ), subject: z . string (). trim (). catch ( "" ), message: z . string (). trim (). catch ( "" ), }); const contactFormSchema = z . object ({ email: z . email ({ message: "Please enter a valid email address" }). trim (), subject: z . string (). trim (). min ( 1 , { message: "Please enter a subject" }), message: z . string (). trim (). min ( 1 , { message: "Please enter a message" }), }); Check to see if the request is a POST by checking Astro.request.method . If it is, commence the work of validating the input and sending the email. I used two different zod schemas to help with parsing the submitted data. The normalizedFormSchema will always return an object containing email , subject , and message properties, defaulting each property to an empty string. The parsed values can be assigned to the default values for the email , subject and message that we set up earlier. Parsing with the contactFormSchema does the real validation. If parsing succeeds then we have all the information required to send an email. If validation fails, we collect the errors using zod’s flattenError function and pass them to the component to render. --- if ( Astro . request . method === "POST" ) { const data = await Astro . request . formData (); const normalizedFormData = normalizedFormSchema . parse ( Object . fromEntries ( data ), ); ({ email , subject , message } = normalizedFormData ); const contactFormData = contactFormSchema . safeParse ( normalizedFormData ); if ( contactFormData . success ) { // The data is correct, send the email } else { errors = z . flattenError ( contactFormData . error ). fieldErrors ; } } Hook up the Resend API Now that the data is validated, we can send the email. It’s easiest to send with Resend using the Resend Node.js SDK : npm install resend Import the SDK at the top of contact.astro : --- export const prerender = false ; import { RESEND_API_KEY , RESEND_TO_EMAIL , RESEND_FROM_EMAIL } from "astro:env/server" ; import { Resend } from "resend" ; Then, when the data has been parsed and validated correctly, create an instance of the Resend client and use it to send the email: --- // validate the data if ( contactFormData . success ) { const resend = new Resend ( RESEND_API_KEY ); const { error } = await resend . emails . send ({ to: RESEND_TO_EMAIL , from: RESEND_FROM_EMAIL , replyTo: contactFormData . data . email , subject: contactFormData . data . subject , text: contactFormData . data . message , }); if ( error ) { throw new Error ( `Failed to send contact email: ${ error . message } ` ); } successMessage = "Thanks for your email, I'll get back to you soon!" ; } else { errors = z . flattenError ( contactFormData . error ). fieldErrors ; } --- Here we are using an email address on our own domain to send the email since we can’t send on behalf of the user using the contact form. We set the user’s email address as the replyTo property, so that when you hit reply in your email client, it goes back to them. If Resend returns an error, we throw it so that Astro responds with a 500 status and our monitoring can alert us. Otherwise, we set successMessage and render the confirmation. Spam protection I initially built my contact form like this to keep from publishing my email address on the public web and avoid getting picked up by spammers. While that worked, it did not stop another class of bots from finding the contact form and filling it out themselves. I was so excited when I got my first email from the form, and then it turned out to be spam anyway. So, while this is how to set up a contact form using Astro, there is more work to do before you publish: you need to stop bots from abusing it. Ultimately, I put Cloudflare’s Turnstile in place, though you might consider things like Google’s reCAPTCHA or hCaptcha . In another post I’ll share how I implemented Turnstile. Happy emailing This is how to build a contact form with Astro and Resend. I like how Astro’s pages allow you to do all of this in one file, and how sending the email with Resend is just a couple of lines of code. Thankfully, once I’d shut down the bots, I’ve also received some really useful emails through this form. I hope this is a helpful look at how to add just a touch of interactivity to an otherwise static site using Astro.

Thursday, 17 September 2026

  • CSS Articles by Temani AfifMore Front-end Bloggersread at source

    Extracting Grid Information Using CSS

    Extracting Grid Information Using CSS Read the full article online

Monday, 14 September 2026

  • Dan DaviesMore Front-end Bloggers7 min read

    A view from inside the Novira Cymru Premier

    This article reflects my personal views and experiences as a director and media officer at Holywell Town. It is intended as a constructive contribution to the conversation around the new Cymru Premier. The expanded Novira Cymru Premier has brought 16 teams together in Wales’s top tier, creating a league with more visibility, more big occasions […]

Sunday, 13 September 2026

  • Adam SilverMore Front-end Bloggers2 min read

    Why I wait for research to prove something is needed before it’s added to the UI

    Last week, a colleague gave feedback on a prototype I’m working on - a flow that helps users review a case. The UI has an accordion of documents. You can select text within each document to annotate it: Here’s what the page looks like when the accordions are collapsed: The…

Friday, 11 September 2026

  • DigitalA11YMore Front-end Bloggersread at source

    How to Test Touch Target Size for WCAG Compliance

    Has this ever happened to you? You’re scrolling through an app or website on your phone and accidentally tap a link or button you never intended to select. Or perhaps you’re trying to complete an online purchase and, instead of pressing the small “Buy Now” button, you accidentally activate a neighboring link because the controls...

Thursday, 27 August 2026

  • Scott Hanselman's BlogMore Front-end Bloggers3 min read

    Debugging my new network, when 10 Gigabit Ethernet Runs at 300 Megabits

    I've been moving my home storage over to a UniFi UNAS Pro 8 as part of a larger homelab moderization . My main IRONHEART (the ultimate PC from a few years back) desktop now has an Intel E610-XT2 10GbE card, the NAS is on 10GbE, and there's a Minisforum MS-01 miniPC on the same network with a 10GbE SFP+ connection running Immich and Portainer and a few other things. Everything says 10 gigabit. Windows says 10 gigabit. UniFi says 10 gigabit. SMB copies are using the correct NIC but my file copies are running at around 100 to 200 megabits per second which is sad making. Naturally, I blamed the NAS, and the spinning rust within. The UNAS has six 16 TB spinning disks in RAID 6 and a pair of NVMe SSDs being used as cache. I'm also running Immich on the MS-01, with its photo library living on the UNAS, so there are lots of thumbnails, metadata reads, and little background writes happening. All seem like reasonable suspects. I switched the UNAS SSD cache from read-write to read-only. No meaningful difference. I stopped Immich completely. No difference. I looked at iostat ; the disks weren't saturated. We looked at SMB signing and Windows Defender network scanning. Still slow. Then I stopped testing the NAS and ran iperf3 directly between the Windows desktop and the MS-01: iperf3 -c 192.168.1.222 -P 4 133 Mbit/sec Oops. The reverse test was better, but still wrong: iperf3 -c 192.168.1.222 -P 4 -R 1.33 Gbit/sec That's weird. Now the disks, SMB, Immich, RAID, and the NAS itself were completely out of the equation. This was a Windows/NIC problem and it's weirdly asymmetrical. Looking at the Intel adapter statistics shows me... Get-NetAdapterStatistics -Name "Ethernet - 10 Gig Intel" There were nearly a million ReceivedDiscardedPackets . During one ten-second iperf3 test, the counter increased by another 268. Why? The E610 driver had its receive buffers at the default 512 , although it supported up to 4096. I increased them. I love an increased buffer. Set-NetAdapterAdvancedProperty ` -Name "Ethernet - 10 Gig Intel" ` -DisplayName "Receive Buffers" ` -DisplayValue "4096" The discarded-packet count during the next test went from 268 to zero , and receive throughput jumped from 1.33 Gbit/sec to 5.15 Gbit/sec . The transmit direction was still terrible, basically 313 Mbit/sec . The next experiment was disabling Large Send Offload (LSO) V2 for IPv4: Set-NetAdapterAdvancedProperty ` -Name "Ethernet - 10 Gig Intel" ` -DisplayName "Large Send Offload V2 (IPv4)" ` -DisplayValue "Disabled" Then I ran the same iperf3 test again. 7.03 Gbit/sec That's not a typo. 313 Mbit/sec to 7.03 Gbit/sec by changing one NIC setting. Sweet sassy molassey. LSO exists for a good reason: Windows can hand large TCP buffers to the NIC and let the adapter/driver segment them into network-sized packets, reducing CPU work. Microsoft does, however, explicitly point out that segmentation offload can reduce maximum sustainable throughput with some network adapters/configurations. LSO is usually useful, but not in this case. In my particular combination of Windows and the Intel E610-XT2, something in the IPv4 LSO path was very, very sad. I don't yet know whether this is an Intel driver bug, firmware issue, Windows interaction, or something particular to this machine, so I wouldn't turn this into random tech blogger advice that everyone should disable LSO. Measure first, cut once. Er, twice. Just stay woke. Finally I went back to the test that started all this and copied the same large file to the UNAS and Robocopy reported: Speed : 350,201,354 Bytes/sec. Speed : 20,038.682 MegaBytes/min. About 350 MB/sec , or 2.8 Gbit/sec of sustained real-world SMB writes to a six-disk RAID 6 NAS. That's much more like it. The useful lesson isn't "disable LSO." It was that when storage is mysteriously slow, eventually you have to stop testing storage. iperf3 removed the NAS, filesystem, RAID, cache, SMB and disks from the experiment in one move. Once the raw network was also slow, the problem became dramatically smaller. And, sometimes the little checkbox labeled Large Send Offload is capable of making your 10 gigabit card run like it's 2004. TL;DR - with LSO V2 for IPv4 enabled, Windows-to-Linux iperf3 managed about 313 Mbit/sec . Turning off that single offload took the exact same test to 7.03 Gbit/sec . I’m deliberately saying on this machine because LSO is normally useful and this isn’t blanket advice to disable it everywhere. © 2025 Scott Hanselman. All rights reserved.

Sunday, 23 August 2026

  • Chen Hui JingMore Front-end Bloggers4 min read

    I still like writing websites by hand

    Back in 2020, I built Alex's website. He has not changed it since then. That's on him, not me. I think I first met him in 2017. It is now coming up to 10…

Monday, 17 August 2026

  • Manuel MatuzovićMore Front-end Bloggers12 min read

    My HTML boilerplate in 2026

    Every element I use for the basic structure of a HTML document, with explanations why. Five years ago, I shared the HTML boilerplate I use for most of my projects. Since then, a lot has happened in HTML. It's time to give it an update. My boilerplate This is the final document.…

Friday, 14 August 2026

  • Monica DinculescuMore Front-end Bloggers3 min read

    Classic dopamine economics

    I keep forgetting to write a post. Instead what happens is I leave myself little bread-crumb trails of notes (“chitaru shiota exhibit; can’t relate”, “birdhouse craft”), like a woman fleeing a crime scene that she will later have to investigate. They just sit there. A little…

Saturday, 8 August 2026

  • Big MediumMore Front-end Bloggersread at source

    The Right to Resist Optimization

    “If machines are great at the things we’ve long thought to be uniquely human, maybe we’ve been misunderstanding humanity all along.” This weekend I picked up a physical copy of The Humanist Review of AI at Casa Magazines , a collection of essays on AI by technologists, academics, and philosophers compiled by Mustafa Suleyman, the head of Microsoft AI. Audrey Tang’s essay, AI and democracy: the right to resist optimization , stood out for the way it reframes a conversation that’s become a little bleak. The reassurance we keep hearing goes something like this: Sure, LLMs can write songs and novels and will probably make movies soon, but don’t worry—humans will always have taste . It’s a pretentious consolation, and probably not even true. A probabilistic system armed with design principles can make evaluations of taste just fine. For better and worse, humans are no longer unique for having ideas or for writing them down. What remains unique is our ability to stand behind our creations—to be accountable for them and to love them. People flock to IMAX theaters not out of love for the film format, but because a director like Christopher Nolan made a stand for it. It’s the person behind a creation that gives it meaning; the audience trusts him . Tang, like our own Josh Clark, argues that Turing’s imitation game has been a trap from the start. We shouldn’t build machines to imitate us—and we shouldn’t evaluate ourselves like machines either. She points to social media, where content is ranked by engagement, as a case of humans optimizing themselves against a machine’s metric. It’s hard not to think of education, where standardized tests reward answering questions on short passages, so classrooms assign excerpts instead of books—and students stop reading books at all. We keep building the very world we say we’re afraid of. So what should we be cultivating instead? Tang offers a starting place, naming the skills she sees as essential for the future: originality, expression (getting your ideas across to other people), and morals. It pairs well with the argument we make in the first chapter of Sentient Design —that there have always been many kinds of intelligence, and the arrival of machine intelligence should sharpen rather than diminish our sense of the human ones. “What ways of becoming human should education cultivate when many forms of performance can be automated?” My answer is that education must move away from ranking compliant output and toward cultivating interpretive courage, collaborative range, ethical imagination and the capacity to participate in revision without losing face. The RIght to Resist Optimization | The Humanist Review of AI

Thursday, 23 July 2026

  • Max Stoiber's EssaysMore Front-end Bloggersread at source

    Build something to disagree with

    A rough first version gives everyone the same thing to react to. Make ideas concrete before debating them.

Sunday, 5 July 2026

  • Modern Web Development with ChromeMore Front-end Bloggers4 min read

    The web the model sees

    A run of recent posts on aifoc.us that I did not plan as a series but which turned into one. The thread is that the web a model sees is staler and thinner than the one you ship, and I have mostly been trying to find ways to see it.

  • swyxMore Front-end Bloggersread at source

    What America has meant to me

    Every time I have given up on America, it has been a mistake. And yet, America has never, ever given up on me.

Friday, 3 July 2026

  • Salma Alam-NaylorMore Front-end Bloggers12 min read

    Goodbye, forever, probably.

    Why I’m leaving developer relations, and why I’m not telling you what’s next.

Sunday, 28 June 2026

  • Jack FranklinMore Front-end Bloggers5 min read

    AI loops: who pays for the tokens?

    A recent trend in AI has become this idea of "loops". Rather than you doing prompting and working with the AI to design and implement, you instead give it a higher level goal and let it roll. You build a system to let the AI make decisions, build and verify its work, all with…

Sunday, 21 June 2026

  • Aleksandr HovhannisyanMore Front-end Bloggersread at source

    How to Use an Android Phone Camera in OBS

    Mirror your phone's camera to your computer with scrcpy, and record it with OBS.

Thursday, 11 June 2026

  • Ashley NolanMore Front-end Bloggers2 min read

    Hello again (and a new look)

    After far too long a break from writing, I've given my site a fresh coat of paint.

Thursday, 7 May 2026

  • Mark's Dev BlogMore Front-end Bloggersread at source

    My Thoughts on AI, Part 2: Agent Setup, Workflow, and Tools

    Introduction Hopefully you've already read Part 1: Fears, Opinions, and Mental Journey so you understand how I ended up with this mindset and approach. Or maybe you saw how long it was and just immediately bailed out :) Welcome either way. Part 1 was the braindump. Story, thoughts, feelings. Here's the part that probably more of you are interested in :) What my actual agent setup and dev workflow looks like. How I approach using AI for writing code, what tools I use, how I have them configured. You can see a cleaned-up version of my config at https://github.com/markerikson/opencode-config-example - follow along in that repo for the pieces as I describe them here. As I said in Part 1: I am not trying to sell anything, change anyone's mind, or say I am an expert. I don't have the answers. BUT I DO HAVE SOME OPINIONS NOW! :) I'm not saying that everybody should follow them, but this is where I've landed. Introduction Agent Setup Overview Agent: OpenCode and CodeNomad Model: Opus 4.6 IDE / VCS: VS Code and Fork Daily Development Workflow Parent Orchestrator Session for Project Management Subtasks for Development OpenCode Config Permissions Management File Reads Code Structure and Search Context Management Session History and Search Dev Plans Repo and Management Scripts Plan Management Issues Personal Dev Plans Repo Workflow Artifacts devplans.ts Automation Script Progress Updates and Subtask Handoffs AGENTS.md Commands and Skills Project Setup Progress and Subtask Management Task Tracking Other Commands Other Skills Config Improvement Process Potential Future Workflow Improvements Final Thoughts Agent Setup Overview Agent: OpenCode and CodeNomad I've settled on OpenCode as my agent of choice. I quickly decided I couldn't use TUIs for any development work. I've always been a GUI / IDE user anyway. I briefly tried both Claude Code and OpenCode TUIs, and bounced off hard . It's not that I am against terminals or CLI tools, I use a lot of them! But I also like having multiple tabs, my choice of coding font, syntax highlighting, and even just straightforward copy/paste abilities. Maybe I gave up too quickly, but I really struggled to get any of the TUIs to do that. I know Claude Code is the market leader for coding agent. Maybe if I gave it another shot I'd find some use out of it. On the other hand, I've always been enough of a tinkerer that I do customize my tech and tool setups. Yeah, I'm a lifelong Windows user, but I've got a comprehensive suite of tools and techniques and customizations I've built up over the years. I use Android because I want to fiddle and customize and configure the system the way I want it. OpenCode fit that bill when I tried it. It works well for me, and I'm happy with it. So if I'm not using the TUI, what's the alternative? I found a great third-party OpenCode web UI called CodeNomad . Tried it, loved it, works great . My personal laptop is all Windows, but my day job is WSL within Windows. I can start CodeNomad's server from within the WSL environment, browse to the web UI from the Windows side, and not have to deal with any cross-platform filesystem limitations. I can have multiple sessions open in one browser tab (with a tabbed UI inside of the page), or have multiple browser tabs talking to the same server. I get full GUI copy and paste, good tool and edit/diff views, and a lot more. So, I now am actually doing my primary development there in CodeNomad. Not an IDE. Model: Opus 4.6 We primarily use Anthropic models at work. Honestly I've never even tried Gemini / Codex / GPT-whatever / Kimi / etc. I've really only used Opus and Sonnet. Opus 4.5 and 4.6 have both produced great results for me. Sonnet is decent. There's probably a lot I'm missing. I don't want to burn a lot of time trying out models and running evals every few days, or switching back and forth just to eke out another 1% gainzzz. That's fine. I just need something that works well enough for me and that I'm comfortable with, and Opus 4.5/4.6 have fit that bill perfectly. (As of writing, I haven't tried out 4.7, and I'm kinda scared to. Too many weird reports about its behavior.) Also worth noting that I'm using via API, not Max plans. IDE / VCS: VS Code and Fork I've been using VS Code as my editor and IDE of choice for many years. It's not perfect, but it works. Ironically, I now use it more as a file and diff viewer than as an editor :) I mean, I am writing this blog post itself in VS Code. But for daily dev work, I do the session driving in CodeNomad in the browser, and then I flip over to VS Code to review and commit the diff. Honestly I don't like VS Code's Git panels and UI! They feel very awkward. The diff hunk staging view in particular is bad , especially compared to other IDEs like WebStorm or purpose-built Git GUIs. (Think I saw they maybe made some improvements in the last couple VSC releases - I haven't updated lately.) Fork has been my Git GUI client of choice for the last few years. Excellent, absolutely worth it. The issue here is that all my work repos are inside the WSL environment. It's technically possible to point Fork at a cross-platform WSL share of the repo folder, but the file changes tend to not refresh well, so I've mostly fallen back to just doing Git diff operations in VS Code. I think there may be some Fork tweaks that make it work better in WSL - haven't dug into those. I do know there's some Linux-native Git GUIs out there, I just haven't spent time evaluating those lately either. Daily Development Workflow My workflow is: A long-running "Orchestrator"-mode parent session with the overall context for the major development work that I'm doing. This session's job is solely to spawn child subtasks where I do the real work interactively. Child subtasks dedicated to some subset of the actual work. This may be codebase research and exploration, feature planning, or actual code development. These are highly interactive - I spend all my time discussing, directing, and driving these subtasks. The core principles here are: I'm in control. I'm the one who knows what I'm working on and what I want to accomplish. I decide what the tasks are, and how to accomplish them. I decide when to move from research to implementation, when to keep digging further or pivot a session from the original goal to a side quest, and when a task is actually done. I need to be mentally engaged, understand what is happening and why, review the code, and actually commit it when I'm satisfied. Most of the time I have one active parent session, and 1-3 active subtask sessions. I do bounce between the active subtasks and context-switch. Normally these are all still part of the same actual workstream. I have tried running sessions for 2-3 different workstreams at the same time, and it's tough, so I mostly stick with one workstream at a time now. I'm sure a lot of folks will say "but that's so slow, you could be moving so much faster!". I know. That's the point :) I'm intentionally choosing to limit the workflow to what I can manage in my own head, so that I am still fully mentally engaged and building my own understanding of the system. I also specifically aim to keep as many of the moving pieces as deterministic and scripted as possible, especially for things that can be automated like file management tasks. Parent Orchestrator Session for Project Management I start every new parent session by running my /context command. This tells the agent to read current-focus.md and the last 2-3 days worth of progress file entries. That way it has baseline knowledge of the current repo, recent work, and what I'm actually working on. From there, I give specific instructions for whatever I'm working on. This is usually several paragraphs of "here's the overall goal I'm working towards today, here's what I'm specifically trying to accomplish, here's how I want to get there". Then I specifically instruct the orchestrator parent session to spawn one or more subtasks to do the actual work. It then sits and waits for those to complete. OpenCode subtasks are essentially async functions with a return value, where the subtask can return some message to the parent. However, the child often returns a response with the initial result, but I then keep driving the subtask much further and do a lot more work, so the initial response doesn't capture the actual work accomplished. Another problem is that if I don't like what a subtask is doing and hit the "Stop" button in that session, it cancels the response to the parent and returns an empty value. The orchestrator has a bad habit of seeing that empty response and saying "oh, the child didn't complete, let me spawn another subtask to pick up where it left off". I've had to specifically instruct it " never spawn more subtasks until explicitly told to do so !" My instructions for spawning a subtask are surprisingly lax in some ways. I've done a bunch of work to give the orchestrator context on what I'm doing, why, and what the next goal is. At that point, I often say "spawn a new subtask to....", and leave most of the details up to the orchestrator. Sometimes I'll give fairly specific bullet points: "have the child read files A, B, and C for context. Then, come up with an initial plan to build this feature, and pause. I'll review and confirm implementation." Other times, especially when the parent session has gone on for a while and the orchestrator has already spun up a half dozen child tasks for earlier steps, I might just say "yep, kick off phase 3", but by that point I have high confidence that we're on the right track and there's an established pattern for what we're doing. I've had some parent sessions last up to a couple weeks as I'm focused on an ongoing effort. Other times it might be a fresh parent session each day. Either way, it's about the overall goal that I'm working towards right now. Here's what a typical orchestrator session looks like - the tail end of the /context being loaded, and my initial instructions for what I want to do in this session. Subtasks for Development Subtasks are where I do all the actual work. I let the orchestrator write up the full prompt for child subtasks. This is normally enough to get the task started, read a bunch of files, orient itself, and "get the full picture" :) The entire subtask session from there is highly interactive. If it's a research or planning session, I review the results and provide feedback on the output. If it's a coding session, I look at the initial plan for the changes and provide specific guidance and direction. I want to be very sure both me and the agent understand what we're trying to do, why, and how. I'll provide guidance on specific techniques to use, ask questions about edge cases and ideas, have it expand my own thinking as much as possible. I only tell it "okay, go make these changes" once I'm very sure about the intent. I usually try to keep an eye on the agent as it's making edits. I don't want to have to explicitly approve operations as it's running (and we'll talk about permissions management more later), but I at least want a sense of what it's doing and if it looks like it's heading in the right direction. If not, I'll mash the "Stop" button and course-correct. Once the edits are done, I'll run / test / etc as needed. I also try to review the code as much as possible. I then do the actual Git commits myself - staging, messages, commits. In a lot of ways this is "one developer workflow, but with extra steps". Fair :) The speedup comes from the agent's ability to do the research for me, expand "here's what I want to do" into a plan for how to do it, and then turn the "what and how" plan into specific code edits faster than I can. My fingers are fast, but my brain always had to work through the intent first. Here, I get to focus more on the intent and the desired behavior, and let the AI define most of the code-level changes to accomplish that. I frequently drive subtasks for extended periods of time. I try to keep a given subtask on track, but sometimes I end up veering into side quests because it's easier to keep going here rather than start up a whole new subtask and load context for the freshly discovered problem all over again. Early on, this definitely led to hitting session context limits, which forced me to create commands to reload an entire session's transcript and run those after the entire session got auto-compacted. Now that I have the OpenCode Dynamic Context Plugin and better tools and instructions for reading files, it's rare for even an extended session to end up over 100K context. The agent is very proactive about compressing recent tool calls and discussions in order to keep context manageable, and this seems to produce much better results than a big-bang "summarize the entire session so far" compaction. (Granted, sometimes it over -compresses recent chunks of the discussion and gets a bit confused on what we were doing :) ) Once I am actually ready to wrap up a given subtask, I specifically manually trigger the two record keeping commands. /progress tells the subtask to append a new "what did we accomplish?" entry to today's progress log file. /subtask-complete writes a standalone version of that update with more details, suitable for the parent orchestrator session to read. I then switch back to the parent session and run /subtask-resume , which reads all outstanding subtask handoff files so it knows what the N most recent subtasks accomplished. There's some duplication here, but I view it as /progress is for the permanent record of what I did today, /subtask-complete is the function return call results for the subtask to ensure the parent session knows where things stand. Here's a typical child subtask, in this case for working on Replay MCP's ReactComponent MCP tool. First, the initial orchestrator-provided prompt: Then my responses to some of the agent's analysis and implementation suggestions: and finally nailing down some design decisions: OpenCode Config I have a very customized OpenCode config and setup that I've built to directly support that workflow. Permissions Management I don't YOLO or --dangerously-skip-permissions . I run my agents directly on my own machines, no sandboxing. That also means that I need some amount of safety checks on commands that get run. I do want to eliminate as many unnecessary permissions prompts as I can. Even if I'm watching and directly driving an agent session, it does get very annoying to see a bunch of permission prompts in the chat session blocking and waiting for my approval, when they're pretty clearly harmless. So, as I said in Part 1: determinism. I generated a custom OpenCode plugin to auto-approve as many Bash commands as reasonable based on the contents. It's decently sophisticated. There's a very long regex-based list of known safe commands and subcommands that get auto-approved, as well as a similar of known dangerous commands that will get blocked. It actually does Bash parsing and tries to deal with heredocs and command substitutions. The bigger question is how this actually works with OpenCode at all. OpenCode refactored their whole permissions and plugin system a few months ago. There was already a "permission.ask" event trigger that allowed plugins to actually return a result, but in the refactor that got disabled. I filed an issue, other people have filed PRs, those haven't been merged. So, I've been maintaining a small local fork of OpenCode that reimplements that functionality. That allows my plugin to actually manage permissions. I saw Claude Code now has a "not quite YOLO but let the agent self-approve commands" mode. That's nice, but why rely on more agent calls and more tokens when you can just parse and manage the commands deterministically? :) The big loophole here is dynamic scripts - bun -e , node -e , python3 -c . Agents love those. They're really useful! Don't even bother writing a script file to /tmp , just bun -e "someCodeHere()" and get the results. Really useful when introspecting some data files. Obviously this means the agent could trivially smuggle through code that starts nuking folders or uploading my secrets to the mothership. In practice: I'm not sure I've seen my agents actually try to run a command that would be truly destructive. I've got these guardrails in place, and to some extent I haven't seen evidence that they're necessary . The permissions plugin does try to do some additional scanning of inline eval scripts for blatantly obvious calls like unlink() and flags those entire commands for approval. It's a tradeoff I'm happy with at this point. File Reads OpenCode has a Read tool, same as every other harness. It works. But agents default to just reading massive amounts of file text, over and over, both to learn the codebase and to remind themselves of what they've seen already. I found a file read caching tool called cachebro that is available as an MCP. It checks file access times and hashes, and if the file hasn't changed since the last read, the tool returns a message saying "this hasn't changed". I've told my agent to default to using cachebro for file reads. Unfortunately, the cachebro MCP read tool doesn't interact with OpenCode's own "file last read" logic. That meant that if my agent tried to write to a file, OpenCode would return an error saying "you must use the Read tool first", and then it would have to actually call Read and it's all a waste of time and tool calls and tokens. So since I was already maintaining a small running fork of OpenCode to handle the "permission.ask" event, I just added another commit to the fork that exposed OpenCode's "file access time" calls into the Plugin interface. Then I built my own cachebro plugin that watches for cachebro MCP tool calls, and gets/sets the file read times so OpenCode knows that file's been read. Works great. Code Structure and Search Per above, agents default to just Read for everything. This is awful for codebase exploration. Read 10-15 files just to trace dependencies and imports. Lots of extra wasted code text bloating the context. Don't do this! I've tried out a half-dozen different MCP tools that do full codebase parsing and provide tools to query structure, dependencies, outlines, and relevant chunks of code. Currently, I use grepika and tilth via MCP, and get great results. Highly recommended. I again have my AGENTS.md with instructions to always use those as the primary file reading options, and I consistently see my agent using them and intelligently only loading relevant parts of files. I've also previously tried ckb (CodeKnowledgeBase). It's got a massive set of tools for querying structure and blast radius, and I've wanted to use it, but I've run into a few problems with indexing not working or tool calls timing out. Been playing with ariadne , and I'm constantly keeping an eye out for other codebase indexing tools. Context Management Per above, I do all my work exclusively in subagent sessions that I drive myself. This means my parent orchestrator session doesn't have any issues with maxing out the context window and needing to compact, but the child tasks do. I did pretty frequently hit 160-170K context and run into auto-compaction. I hated it. The auto-compact summaries were adequate , but inevitably there'd be a bunch of details I cared about that would get lost. At first I built some dev scripts commands that would read the OpenCode session JSON files, filter out tool calls, and export the meaningful message contents out as a complete Markdown file. I built a /session-reload command and skill that would force the agent to run the export command, read the entire exported transcript, and then pause. However, grepika really reduced the amount of code that was bloating context. That helped. Then I found the OpenCode Dynamic Context Pruning Plugin . Instead of waiting until your session is almost at full context and then doing a big summary of the entire session as a replacement, which would be really lossy, it gives your agent a compress tool that it can use at will to compress and summarize chunks of your session (like a bunch of exploration file reads, or earlier messages as you switch focus to a follow-up effort). This means there's more of the session messages that stay exactly as-is, there's less time spent compacting, and it's much rarer that one of my subtask sessions actually nears max context and has to compact everything just to reset. Ironically, I really found a great working combo of tools right before Anthropic shipped 1.0M context windows by default for everyone :) But seriously, in the last couple months since landing on this combo of tools and plugins, I find that even a very long-running technical subtask session rarely gets above 100K context, thanks to grepika and cachebro minimizing file reads and the agent happily compressing earlier chunks on the fly. I know this does mean you might have some cache invalidations that could bump cost because it's no longer just the one latest message at the end of the session that hasn't been seen by the server. But on the flip side, keeping the actual total context size smaller seems to pay off, and it's not like the agent is calling compress every other turn. I was using the rtk Rust CLI tool to automatically compress the output of tools like grep to save on tokens. Unfortunately I saw too many cases where the agent got stuck in a loop trying to call grep , rtk grep would change the output too much, the agent got confused and tried again, and it just wasted time and tokens. So, eventually disabled rtk . Might come back to it at some point. Session History and Search As mentioned, I initially built some custom scripts that would find the right session JSON files and export as separate Markdown transcripts with just the message text, no tool contents. OpenCode 1.2 switched to storing sessions internally in SQLite. I held off upgrading to 1.2 for a while because I had all my custom scripts and commands and didn't want to take the time to rewrite them. But, I finally did, and that actually simplified things quite a bit. My previous /session-reload command told the agent "run the export session -type command, look at the list of most recent sessions it gives you, find what you think is the right Markdown file based on your own context and instructions, and read that". Kind of awkward, left room for error. After rewriting my own session history plugin to read from OpenCode's own plugin/internal client.session object, that all went away. Instead, I have a reload_session tool that can just directly grab the list of messages from the plugin API using the session ID, filter, construct the Markdown contents, and directly return it as the tool call result. No file path or "match up the session" steps needed. It was also trivial to throw together search_sessions and read_session tools. They're currently pretty dumb and just do basic regex searches on session contents, no vector DBs or similarity scores or anything. But they're pretty useful even in that form. Dev Plans Repo and Management Scripts Plan Management Issues During my initial couple months of using KiloCode, I found myself with the same proliferation of Markdown plan files that we've all run into. So where do those go? The agent wants to default to writing them to the root of whatever repo you're working in. I made an effort to redirect it to write them to a ./docs folder, although in our main backend repo that already existed so I had to resort to ./docs/merikson . Some of these plan files were worth committing or preserving, even if just for my own reference later. Others weren't. So where do the plan files go if this is a shared repo? I really didn't want to pollute a shared repo and commit history with dozens of my own personal semi-ephemeral plan files, or even the maybe-more-widely-useful architectural writeups. Personal Dev Plans Repo I decided the best option was to set up an entirely separate personal development doc knowledge base repo, just for myself. I dubbed it dev-plans . That would give me a consistent place that I could store all my own Markdown artifacts and knowledge, commit it, save those for future reference, and not pollute the shared actual repo Git history. My dev-plans repo structure is: /dev-plans /personal /redux /$PROJECT1 /architecture /features /progress-updates /research /subtask-handoffs current-focus.md QUIRKS.md /replay current-focus.md is intermittently updated whenever I feel I'm significantly shifting gears or focus on a repo, or completed a major chunk of work and the "what I'm working on now" section should reflect that. QUIRKS.md is more of a project structure, known actual quirks or patterns, things to remember document. Every file other than the two fixed current-focus.md and QUIRKS.md files starts with a YYYY-MM-DD prefix, such as features/2026-05-06-some-feature.md . I've got some archival scripts set up to move older documents from the flat folder structure into a nested YYYY/MM structure to keep things a bit more readable, but haven't done much with that yet. I suspect I'll need some tools to help index the documents when I do that. Workflow Artifacts architecture is meant to be longer-lived explorations of the codebase structure and patterns. Full-blown "what do we know about this project", vertical "trace through this feature or data flow path", reference material features is WIP development plans. Here's the next thing we're going to build, we've turned this into a concrete plan, use this as the basis research is more of a grab bag. Sometimes it's scanning the codebase for concepts, other times it's research dives through Github and NPM for relevant concepts progress-updates is the daily dated appended progress entries, subtask-handoffs is the individual handoff files that get automatically archived as soon as they're read devplans.ts Automation Script I've settled on using Bun with TS scripts for a lot of my personal needs and utilities. I've tried to automate a lot of the common tasks I saw consistently pop up when interacting with the dev-plans repo. I created ~/.config/opencode/scripts/devplans.ts and have fleshed it out over time with a variety of commands the agent uses all the time. Currently, that provides: /** * devplans.ts - Unified dev-plans CLI helper * * Commands: * devplans info Get project mapping info (no side effects) * devplans progress Get/create today's progress file (with late-night date logic) * devplans progress list [n] List n most recent progress files (default 3) * devplans progress append [file] Append entry from JSON file (deleted after read) or stdin * devplans handoff create [slug] Get path for new handoff file * devplans handoff list List files in pending/ * devplans handoff move [file] Move from pending/ to completed/YYYY/MM/DD/ * devplans handoff consume List, read, and move all pending handoffs * devplans doc create Create dated doc (type: feature|arch|analysis|issue) * devplans doc list [n] List docs of type (default 10) * devplans session extract Extract recent sessions, list newest 10 * devplans archive Archive old files to folder/archive/YYYY/MM/DD/ * devplans archive --all Archive all doc folders */ These deterministic commands save a lot of steps that the agent would have had to run itself to figure out what dev-plans folder path matches the current repo, creating placeholder handoff files or documents, and updating progress docs. Most of my OpenCode slash commands start with some variation of "Run `bun dev-plans.ts some-command". I also have a JSON file with folder mappings for my usual repo checkout paths in my personal laptop Windows and work laptop WSL environments. That way the script can just read those mappings and use the known paths. Per the Workflow section, I have a /init command that helps me set up the scaffolding when adding a new project to dev-plans . Progress Updates and Subtask Handoffs The most used subcommands are for progress and handoff . My original /progress command told the agent to actually read today's progress file completely, then append a new section. This became an O(n^2)-type problem as the progress file kept growing over the course of a day. Just reading the file would bloat context, and this was especially bad when the subtask was already bordering on max session context. Now, devplans progress prints JSON output with today's progress file path, but also creates a placeholder temp file and provides that path as well. The agent is instructed to overwrite the placeholder with its actual update, and then runs devplans progress $TEMPFILE . The script then deterministically appends the new section to today's progress doc so the agent didn't have to read that file itself. Similarly, /subtask-complete in the child tells it to run devplans handoff create creates a target file path that the agent can write to, and then when I run /subtask-resume in the orchestrator parent it runs devplans handoff consume which auto-prints all pending handoff files immediately and then auto-archives them. This saves multiple steps of the agent fumbling around. The devplans commands also intelligently handle dates and timestamps - automatically generating file paths with timestamps, figuring out today's progress file, and even assuming that any updates between midnight and 6 AM really belong on "the previous day's progress file" because it's likely I was working late into the night on something. There's still a lot of manual trigger behavior in here, and again I'm good with that :) AGENTS.md My AGENTS.md file is currently about 250 lines (and writing this post forced me to review it and do some reorganizing and condensation - it had gotten rather crufty). It starts with a short personal overview: who I am, day job at Replay, OSS work on Redux. Major sections include: Interaction patterns: I specifically instruct the agent to be keep its responses short and direct, and avoid sycophancy. That includes both descriptions, and acknowledging my instructions. Thinking and problem solving: use critical thinking and be skeptical about assumptions and correctness; stop and rethink problems if stuck; do research, not trial-and-error; state plans and wait for confirmation to check assumptions and confirm user intent Git: never commit, always stop and wait for me to review changes Personal tool environment: personal vs work laptop setups, path management, use Bun for scripting not Python Coding standards: TS usage, running tests, minimizing comments Code navigation: minimize context loading at all times; use grepika and tilth for navigating code, cachebro for other file reads Tasks and behavior: manage todos and progress; be careful counting completion; manage current context Dev plans workflow: use devplans.ts for file management; use of QUIRKS.md and other rules files Subtask spawning and workflow rules: only spawn subtasks when told; verify completion; I make no claims that my AGENTS.md is optimized, correct, or a model to follow :) It's just what I've evolved through my own usage. Commands and Skills Project Setup I have some commands and skills for initial dev-plans setup for a new repo - the usual /init and /architecture -type commands that scan the codebase, do a writeup of the details, do some initial architecture description docs, etc. Don't do those often, nothing special there. Progress and Subtask Management As described above: /progress specifically instructs the current session to create a new entry in today's progress log. /subtask-complete tells a child subtask to record a separate handoff file that can be used as a "return value" to update the parent orchestrator session, /subtask-resume has the parent session read all outstanding handoff files to know what got done. Task Tracking For most of my day to day work development, I've gotten along fine without any explicit external task tracker. I'm the one who knows what I'm working on. For a couple projects, I've tried using dex as a lightweight external nested task tracking CLI. (Think beads , but with way less slop.) It's worked pretty well! I've got a skill that instructs the agent how to use dex efficiently. I'd have the orchestrator session run dex commands to see where we stand in terms of task status, then pass dex task IDs to a subtask and tell it to mark that task as in progress. Similar to avoiding having the agent do any Git commits, I told it not to mark any dex tasks as complete until I explicitly instructed it to do so, and have a /dex-complete command to help with that. Other Commands /session-reload extracts the entire message history of the current session and returns it. Per above, this used to be writing it all to disk as a Markdown file, now it just constructs the transcript in memory from the DB entries and returns it as the tool result. I use this much less frequently now thanks to the OC Dynamic Context plugin and use of better file search tools - now that I have those I rarely get close to 150K+ context even in a long running subtask session. I wrote my own AI-powered code review tool called diffloupe that tries to compare stated change intent vs inferred change intent, and reviews for both bugs and intent mismatches. I have a /code-review command that tells the agent to review the current changes by triggering diffloupe and then report on the results. Other Skills I do have a variety of skills available: several for frontend design and UI work advanced TS patterns Replay CLI and MCP usage Architecture design and feature planning File / codebase search tools Assorted skills explaining how to use diffloupe , dex , and gh Config Improvement Process After I did my initial config and workflow development efforts back in December, I've alternated between periods of leaving it exactly as-is and focusing on just doing work, and getting annoyed with parts of the workflow and making improvements. Generally it's noticing that some particular pain point is becoming an issue - that I keep having to repeat a particular set of instructions, or that part of the workflow could be automated via devplans.ts , or trying out a different codebase indexing plugin that I found. At that point I'll go spin up a new session inside my OpenCode config repo itself, talk through the problem space, and develop the changes accordingly. As a relevant example, just reading AGENTS.md to write this post showed me how the content had gotten somewhat bloated and disorganized. So, I just started up a new session to review it, described my pain points, and the agent suggested a slimmed-down version that retained the key points, moved some of the detailed file tool usage instructions out to a separate skill, and better organized the "how to communicate" and "daily workflow" sections. Done. Potential Future Workflow Improvements I'm pretty happy with the tooling and workflow that I've got right now. The one area where I feel I'm lacking right now is that longer-term memory and context. The system I've got is great for "what is the repo we're working in?" and "what's the current set of tasks?", but I'm finding I have to do a lot of work to dig up other recent sessions where some decision was made or a research document was generated, and feed those back into the current session. I need something that helps index or scan generated planning and progress files and dynamically feeds in relevant results to the current session, or MCP tools that the session can use to scan already-indexed files. I also don't have any kind of automatic "scan recent sessions for common patterns or corrections or learnings, and extract workflow improvements" system. I do instruct agents to include possible learnings in the progress and handoff artifacts, and sometimes those trickle over to updates to QUIRKS.md , but I feel there'd be value in the automatic review process. I am very happy with grepika and tilth for codebase exploration over just reading files manually. I can imagine it would be nice to somehow preload more of the codebase into a given session so it doesn't have to re-explore some of the same files each time Code review and ensuring intent are still hard. diffloupe has been useful for doing some review checks. I intended to add my own full code review UI to it, but got distracted and never got back to that. I've bookmarked a bunch of other code review tools and may still investigate some of those. Final Thoughts 6000+ words, and this was with me deliberately avoiding going into full amounts of technical detail :) So there you go. See the example config repo for the actual commands, scripts, and setup. No idea how many people will end up going through here, but as always, hope this info was useful! And more than anything else: whether you use AI to write all your code or write it by hand, I hope that you can find a workflow for yourself that is sustainable, maintainable, understandable, and safely productive.

Wednesday, 22 April 2026

  • Set StudioMore Front-end Bloggers2 min read

    Astro is our preferred front-end platform

    ![The Set Studio logo, followed by a heart, followed by the Astro logo, on a red background](/images/set-studio-astro.png) We’re not usually ones for welding ourselves to a platform or technology, aside from web standards like HTML, CSS and JavaScript. Part of what makes us so…

Thursday, 16 April 2026

  • Harry CresswellMore Front-end Bloggersread at source

    Designing the Morpho album artwork

    Matt and I have been creating artwork for his music for almost 12 years now. It’s a collaboration I’m immensely proud of, and one that offers a welcome change of scene from my day-to-day job of designing and building websites. Morpho , released on Sound Records in November last year, is our most recent project. Our 12th vinyl release and the 1st Matt is releasing using his last name, Benyayer, instead of his pseudonym, Dark Sky. Now, I must admit, I’m no print designer. And, to be clear, this is my one and only what I’d call “graphic design” gig. However, I now find myself in a position where I have a decent amount of experience creating music artwork. More specifically, artwork for records pressed onto 12" vinyl. With that in mind, I figured it might be interesting to share some of the process that went into making the artwork. Planning Projects always start life on WhatsApp, where Matt and I will discuss all sorts of ideas for concepts that somehow resonate with the music Matt has created. For this project, it was important to create something that felt connected to the artwork that we’d already designed for the singles making up the album. A similar vibe, but somehow different at the same time. It had to feel bigger, more impressive, like a season finale. At the start of a new project, Matt creates a shared Google doc, which tends to evolve as we sculpt our rough ideas into a cohesive direction. The document includes the project objective, themes to explore, information that needs to be present on the final product – think track listings, record label logo, catalog ID – and any technical notes that might be useful, such as colour options for the vinyl, who is printing it, and so on. Not a creative brief in the strictest sense, but something not far off. Once we land on a concept that feels right, all other ideas get scrapped. Any references to those ideas get moved to the bottom of the document, for future reference. But, this usually doesn’t happen before we‘ve explored a whole bunch of ideas first. So let’s get into that next. Research Once we have some rough ideas in mind, it’s time to explore them further to see if we can turn any into a solid concept. A large part of that involves going down the rabbit hole, usually online, to research subjects as much as we can. Early in the process we’ll set up a mood board to collect visual references. These might directly relate to a concept, or simply reference a design style or technique that we think could work well and want to try out. Much like the creative brief, we’ll refine the mood board as we start to make sense of our ideas and land on particular concept or direction to explore further. The goal is to get some inspiration for how a concept might translate into something visual. Our wild ideas are usually tamed by what the label is prepared to pay for. No surprises there. So, another important part of our research is to consider what’s possible within the budget, as well as to identify any creative constraints that may cause issues further down the line. We’ll consider print and vinyl pressing techniques, materials we could use, and so on. At this point, we’ll reach out to potential printing partners to discuss our ideas and figure out what’s possible. We’ll also request card stock samples to help us decide on packaging weight and finish. It’s important to get an idea of these things early on. That way we hopefully wont end up designing something that isn’t feasible to create in physical form. Lucky for us, Sound Records had a decent budget and were open to doing something a little different. This gave us a fair amount of creative freedom and presented a good opportunity to work with a laser cutter. We’d been keen on the idea ever since spotting the artwork for Cascade by Bambounouu a few years back. Concept development After pursued a few dead ends, I received the following message from Matt: ”…it could be interesting to look at symmetry in nature and take inspiration from it. Maybe deconstructing and repeating the body parts of a butterfly could be a something to look at. Could be super subtle. Utilise forms found in nature to enhance the function of the design 🤔. Butterflies symbolise transformation and rebirth, which connects to this new project well and the process I’ve gone through moving from Dark Sky to Benyayer.“ This one had promise. We’d worked with symmetry before on Cold Harbour EP . The artwork was based on a photo Matt had taken of Barrier Block , the brutalist style housing estate in Brixton, South London. Exploring symmetry in nature felt like a nice evolution, yet a fun little throwback to 2019, when we created that particular artwork. It also gave us a subtle way to link this new project back to Matt’s earlier work as Dark Sky. The concept felt like a good fit, so we researched it further. Somewhere along the way, this lead us to Belenois aurota , a medium-sized butterfly, also known as the Pioneer White. Two large migrating butterflies followed: Monarch , one of the largest and rarest butterflies seen in here the UK, and Menelaus Blue Morpho , one of the largest butterflies in the world. While the Pioneer and Monarch would steer the rest of the project visually, the Blue Morpho would eventually lead to the album title itself. The Pioneer White, photo by Jaya Shukla The Blue Morpho, photo by Mori M The Monarch, photo by Justin DoCanto Now we had some creative direction, it was time to explore the concept visually, to see what we could create. Design ideation During design ideation, the goal is to figure out how to turn our concept into a piece of artwork. It’s the point we jump into design software, draw on our inspiration, play around with various techniques and create basic mockups to see what we can come up with. For this part, we usually meet up in person to work on the project together. We wanted the artwork to feel alien, like nothing you’ve really seen before. That meant trying not taking the concept too literally. Whatever we ended up creating had to be a subtle abstraction, not immediately obvious. Something to make you pause for a moment, wondering what the hell it is. As with every project, it also had to be appealing to look at. That may sound fairly obvious – it’s a visual artwork after all – but it‘s easy to forget when you’re busy messing about with design software. For every project, we’ll also consider how the artwork will translate into visuals that can be animated. This is important for live shows, social media reels, and so on. Admittedly, this has been an afterthought in the past and a challenge to reverse engineer, so these days we try to account for this early on. With our concept in mind, Matt played around with openart.ai , using it to generating a bunch of new ideas from our visual references. Generated using openart.ai Generated using openart.ai Generated using openart.ai This helped us visualise some interesting, somewhat alien, jellyfish-like looking forms. However, using a butterfly as the source image would often produce results that felt much too literal. Generated using openart.ai Generated using openart.ai Perhaps we didn’t push things far enough with AI. However, ultimately we concluded that although it was an interesting way to brainstorm ideas, it wasn’t a tool we wanted to rely on to produce the final artwork. After some experimentation, we came back to Matt’s initial idea of deconstructing and repeating the body parts of a butterfly. Focusing on the organic shapes found in the wings of the Pioneer White, we created a rough trace in Affinity Designer. The Pioneer White, photo by Divam Suthar Vector trace of butterfly wings Now we had some vector shapes to work with, the next step was to deconstruct them further to create a symmetrical design that felt interesting and a little weird. The process was made much easier once we discovered the symbol tool trick used to create symmetry in Affinity Designer . Your browser does not support the video tag. Soon enough, we realised we were in the process of creating the artwork that would become the laser cut perforations featured on the outer sleeve of the vinyl packaging. We pictured these shapes revealing a graphic on the inner sleeve beneath. This meant we now had to consider an artwork for the inner sleeve itself. Early in the design stage, I’d played around with the idea of a gigantic bitmapped butterfly motif covering the full front and back of the sleeve. Being far from subtle, I’d abandonded the idea. We returned to the idea once we realised the motif would appear more abstract, when folded in half and viewed through the laser cuts, as it would be in its final form. By duplicating a couple of layers, adding a colour overlay, then applying a blend mode, we were able to come up with something that looked much more interesting. Both when seen through the laser cuts, and when the inner sleeve was removed from the outer sleeve altogether. Feeling like we might be on to something, we tried to piece each part together by creating a basic mockup of how the laser cuts might look with the artwork behind. Now it felt like we’re actually getting somewhere. Time to end another late night design session, get some sleep and look at it again another day. Finding the right direction is always a good feeling. You’re on the right track so you can finally let go of all the other ideas taking up mental bandwidth. In our next sessions we could focus on bringing it altogether. Development At this stage, we’ve visually distilled our concept into a clear direction. Now it’s all about developing the final artwork so is ready for production. The first step is to create final digital prototypes. That means creating mockups of the full product packaging. Outer sleeve, with laser cuts and printed elements like track listing and catalogue number on spine. Inner sleeve, on body vinyl labels and the vinyl itself. It’s not about getting it 100% accurate at this point. The goal is to visualise how the final artwork and physical product might eventually look. Then figure out if it works as we’d imagined. One of the harder decisions was whether to cut out the centre of the inner sleeve revealing the vinyl label beneath. This would create an extra challenge, as we then wanted to ensure that the design featured on the vinyl label would line up with the laser cuts on the outer cover. In reality it rarely would, that is unless you replaced the vinyl in its sleeve with perfect alignment and precision. But we wanted to ensure it was, at least, technically possible, to please those like us who obsess over the details. Ultimately we took the risk and decided to go for it. Seeing right the way through to the vinyl from the cover added some extra depth and dimension to the artwork. Given the intricacy of the design, Matt also made a physical prototype for the laser cut cover, using the sample card stock we’d received from the printers. It was important to figure out whether our laser cut design would affect the structural integrity of the outer sleeve. This lead us to remove some of the elements from the final graphic, then space the rest slightly further away from each other, and away from center and the edges. Your browser does not support the video tag. The next step was to turn our digital prototypes into actual deliverables. These are the print-ready files that the printer, and, in this case, laser cutter, can work with. This is the part where we spend way too much time fussing over the details, making sure everything is perfectly aligned and positioned where it should be on templates provided by the printer. To prevent any issues scaling artwork to fit, we always work in design files large enough to translate to 12" vinyl, even during the design ideation stage. Likewise, I’ll always set the colour format in Affinity to CMYK/8 and speak to the printer about what CMYK profile they want me to use. It’s most often Coated FOGRA39 , if that means anything to you. With this set up we shouldn’t have any surprises when the final product returns from the printer. As our design required both laser cutting and printing, we had to split the artwork into four separate files. One file for the laser cut outer. Another for the text and record label logo that would be printed onto the back of the outer sleeve. Then one for the printed inner sleeve. And lastly one more file for the vinyl labels. I like to export and deliver two versions of each file, one with printer guides and one without. That way there’s nothing to dispute later on. I tend to export and deliver all files in TIFF format to prevent any compression, but I know many printers prefer PDF. Production Now we’re at the business end of the project. Time to deliver our print-ready design files for printing and, in this case, laser cutting. The project is out of our hands and down to our chosen partners to turn digital designs into a physical product. My background is in web design. For those that aren’t familiar, it’s an iterative process. We’ll regularly make improvements to a website long after the project goes live. Print design is the complete opposite of that. There’s no room for mistakes and no going back once you’ve delivered artwork ready to be printed. Although there’s a sense of relief that our part is finally over, there’s still that lingering dread that we’ve messed something up and things won’t turn out exactly how we imagined. It’s an anxious wait between delivering the artwork and receiving it back. Fortunately, this time we got everything spot on. Much of that was down to a good amount of patience and two fantastic partners who were happy to answer our barrage of questions. Press on Vinyl did a stellar job on the printing, as did North London Laser on laser cutting the outer sleeve. Unfortunately, we weren’t organised enough to get shots of the print process. But we did manage to get some of the laser cutter in action. Wrapping up Although the progression from concept to artwork might seem fairly linear, I can tell you now, that couldn’t be further from the truth. In reality, designing music artwork is a messy process. At least, it is for us anyway. Until we hit the development and production phases, we tend to move back and forth between stages in no particular order. Often we’ll have an idea for a concept, do some research, mock up some visuals, then scrap the idea altogether and start the process from scratch. Over the years, I don’t think we’ve ever landed on the right concept before we’ve hit a bunch of dead ends first. Things only start coming together once we’ve done this dance at least a handful of times. Usually it’s a simple idea. Something we touched on early on, that needed time, experimentation and going through the motions to reveal itself and materialise. The final artwork is the result of many hours spent playing around with different ideas, parking the ones that aren’t working, then deliberating over where to go next. It takes time and effort to find the right direction. Along with countless emails, WhatsApps, a bunch of late nights, and arguably too much pizza and whisky. The whole project took around 8 months in total. From the moment Matt first briefed me on the project in February 2025, right through to when Matt received the finished physical product in October 2025. It’s hard to say how many hours we actually spent on it. We had the initial concept down within 3 months, but it wasn’t like we were working on it everyday. Often we’ll give it days, sometimes weeks, between design sessions. Giving ideas time and space to evolve seems to be the key. Anyway, we’re both super stoked with how the artwork turned out. A massive thanks to Tom at Sound Records , Antonio at Heartfelt Management , and the folks at both Press on Vinyl and North London Laser , for helping us to bring the project to life and making it happen. I’ve spent this whole time banging on about the Morpho artwork. However, I’d be doing a massive disservice to Matt if I didn’t mention his fantastic music that’s pressed on the vinyl itself. Ultimately, that’s what this project is all about. You can find Morpho on Spotify if you want to give the album a listen. If you’d like to own your own copy and support the project financially, it’s also available to buy directly from Matt’s Bandcamp page , in both digital and physical form.

Wednesday, 18 March 2026

  • Robin OsborneMore Front-end Bloggers4 min read

    Your AI Robo-Buddy Is Legally Required to Grass You Up

    Since it has an interesting overlap in the Venn diagram of “AI” and “data sovereignty”, here’s a brief follow up to my “Kubernetes, I Guess” article… Cloud Act The Cloud Act allows “federal law enforcement to compel U.S.-based technology companies via warrant or subpoena to provide requested data stored on servers regardless of whether the […]

Thursday, 26 February 2026

  • Krasimir TsonevMore Front-end Bloggersread at source

    The naked truth about AI-assisted coding

    In this article, I argue that AI-assisted coding is useful but overhyped. I see real value in speeding up boilerplate and first drafts, but I also see serious risks: weaker developer fundamentals, more technical debt, shallow productivity metrics, security and licensing concerns, and growing pressure on open source maintainers. My core point is simple: AI can help me write code faster, but it still doesn’t solve the hardest part of software engineering - building the right systems that stay reliable, secure, and maintainable over time.

Monday, 16 February 2026

  • Rob DodsonMore Front-end Bloggers10 min read

    How I Built My Mobile Second Brain

    In my last post, My Second Brain Never Worked. Then I Gave It a Gardener , I mentioned that putting my Obsidian vault on a VPS with Claude Code permanently running on it, and being able to access it from my phone, was the real “ah ha” moment for me. A few people asked how I set…

Wednesday, 4 February 2026

  • Eric PortisMore Front-end Bloggersread at source

    Monochrome Summer

Wednesday, 10 December 2025

  • Samuel KraftMore Front-end Bloggersread at source

    Using SF Pro Rounded with React Native

    How to use San Francisco Pro Rounded with React Native

Tuesday, 18 November 2025

  • Jim Fisher’s blogMore Front-end Bloggers1 min read

    The migration SQL should go in the table

    So you run migrate in your dev environment, but it fails: some unknown migration add-foobar has already been applied from some other experimental branch, and the migration tool doesn’t know how to down-migrate it. To fix it, you have to hunt for the branch that created that…

Articles belong to their publishers. This site only collects what their feeds provide.

Updated 1 November 2026 at 14:10