1. Navitve CSS Masonry in 2026

    I’ve been using macy.js to power the photo grid on my photography section for a while. I’m grateful for that little library, but it’s gotten a bit long in the tooth. A commit hasn’t been made to it’s repo in 7 years (though admittedly it doesn’t need one).

    While making some adjacent CSS changes I broke the masonry layout that relies on macy.js, and while fixing it I thought: it’s 2026, why can’t browsers do this by default by now? Turns out they can. CSS natively supports masonry layouts. It’s just behind a flag.

    The state of native CSS masonry

    Designers and developers have wanted browser-native masonry for nearly a decade. Pinterest of course popularized it even though web designers had been using the effect for a while. Rachel Andrew flagged it to the CSS Working Group at least as early 2017. The first real movement came around 2020, when Firefox shipped grid-template-rows: masonry behind a flag, which then triggered years of spec debate across the browsers. The keyword choice alone apparently took years to settle. Chrome and Edge finally added it in version 140 (mid-2025), and the syntax has since landed on display: grid-lanes as part of CSS Grid Level 3. (The MDN page was updated March 9, 2026, which tells you how actively this is still moving).

    As of now it remains behind flags in all major browsers. But that doesn’t mean we can’t use it with a simple JavaScript polyfill.

    How grid-lanes works

    CSS Grid has always known how to make columns. What it couldn’t do natively is pack items into the shortest column — it assumes rows have uniform height, so shorter photos leave blank space where the next uniform row begins. display: grid-lanes fixes this directly. You define your columns, and the browser handles vertical placement automatically:

    css

    #photos {
      display: grid-lanes;
      grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
      row-gap: 4px;
      column-gap: 4px;
    }

    That’s it. No JavaScript, no span math, no layout events to manage.

    Using JavaScript as a polyfill

    Since grid-lanes isn’t in stable browsers yet, a small script can stand in. The approach: set grid-auto-rows: 1px to turn the grid into a pixel-precise coordinate system, then measure each item’s actual height and set its grid-row-end span explicitly.

    The 1px row unit matters most when your gaps are tight. With a coarse value like grid-auto-rows: 10px, rounding errors can introduce up to 9px of phantom space below items — invisible at generous gaps, obvious at 4px. At 1px resolution the span count is exactly the pixel height of the item plus your gap, with no accumulation.

    css

    /* Base: clean responsive grid, no JS required */
    #photos {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
      grid-auto-rows: 1px;
      grid-auto-flow: dense;
      column-gap: 4px;
      row-gap: 0;
    }
    
    /* Native upgrade for supporting browsers */
    @supports (display: grid-lanes) {
      #photos {
        display: grid-lanes;
        grid-auto-rows: auto;
        row-gap: 4px;
      }
    }

    javascript

    function resizeGridItems() {
      const grid = document.getElementById('photos');
      const items = grid.querySelectorAll('.photo-item');
      const gap = 4;
    
      items.forEach(item => {
        const figure = item.querySelector('figure');
        if (figure) {
          const height = figure.getBoundingClientRect().height;
          item.style.gridRowEnd = `span ${Math.ceil(height + gap)}`;
        }
      });
    }

    Wire this to ResizeObserver and image load events. The @supports block means the script never runs in browsers that support grid-lanes natively.

    Three browser states, all handled

    • No JS: clean uniform grid from the base CSS. Not masonry, but not broken.
    • JS, no grid-lanes: the polyfill gives you true masonry with 1px precision.
    • grid-lanes supported: @supports takes over, JS never runs.

    When grid-lanes makes it into stable browsers releases the migration is one deletion: remove the script tag. The CSS is already written for it.


  2. TIL: Setting up OpenClaw on a headless VPS

    I spent Saturday morning setting up OpenClaw on a fresh Ubuntu server.

    OpenClaw is currently the fastest-growing repo on GitHub. People are divided on it. Some see it as the dawn of truly agentic experiences. Others see it as a security nightmare.

    I’m enjoying the energy. As someone who has been around long enough to be called “officially old” by my daughter, this moment feels like the early 2000s. Back then, we shared CSS and AJAX tricks to explore what was possible, not to brag. This feels like a return to that spirit of genuine making.

    The security concerns are valid, so I opted for a Hetzner VPS instead of my home network.

    Securing Access with Tailscale

    I followed a setup guide from Tech With Tim to lock down the server. I configured the VPS to listen only on its Tailscale IP. This keeps the SSH ports closed to the public web. As usual, I also found some helpful tips from Simon Willison.

    This approach simplifies security. I didn’t have to manage complex firewall rules. I also disabled root login and created a standard user account. The server is only reachable when I am logged into my private Tailscale network.

    The OAuth “Chicken-and-Egg” Problem

    Getting the Gemini Pro integration working was the hardest part. Most early adopters seem to prefer OpenAI or Claude. I do too, but I get Gemini Pro for free with Google Fi.

    OpenClaw uses a headless OAuth flow. You open a URL in a local browser and paste a callback URL back into the server terminal. I hit a loop. I couldn’t get the bot to respond on Telegram without a model, but I couldn’t finish the login while the bot was offline.

    I used a workaround:

    1. The Bridge: I set up a temporary OpenAI model to give the bot a brain.
    2. The Ask: With the bot online in Telegram, I asked: Can you change your own model? I want to use Gemini but I can’t get OAuth working on this headless VPS.
    3. The Logic: It gave me instructions how to fix. I replied: Can’t you just do it yourself?

    It did. It was a satisfying moment of agentic behavior that worked better than I expected.

    Kicking the Tires

    I’m not ready to give OpenClaw full access to my data yet. Instead, I asked it to solve a narrow problem. I still love RSS, but most industry signal now comes from X, YouTube, and Hacker News. The volume overwhelms me, and I often feel like I’m missing the important bits.

    I gave the bot my OPML file and a list of X accounts and YouTube channels. I told it to create a daily digest. I also asked it to fetch the top 20 posts from Hacker News and filter for keywords like “design,” “ux,” and “ai.”

    It built a decent digest. But after a few rounds of refinement, I hit a wall:

    Cloud Code Assist API error (429): You have exhausted your capacity on this model. Your quota will reset after 17h33m16s.

    I still had 100% of my tokens left, but I had triggered the API rate limits. It was a useful reminder of the constraints of these “free” subscription-based models.

    What’s Next

    I’ve updated OpenClaw to default to Gemini Flash. I’ll only use Gemini Pro for complex tasks. Flash has much higher limits, so I should be able to avoid “API jail” in the future.

    I still haven’t named the bot. When I asked for its preference, it gave me a few options:

    Since I’m living on your VPS and helping with technical stuff, here are a few directions we could take this:

    1. The “Tech-Savvy Sidekick” (Default)
      • Vibe: Casual, capable, enthusiastic about code and Linux. Uses tech slang when appropriate. Like a smart coworker who’s always down to help debug.
      • Creature: A digital mechanic or a helpful daemon.
      • Sample: “Yo Kai, I deployed that script. It’s running smooth, no errors in the logs.”
    2. The “Digital Butler”
      • Vibe: Polite, precise, slightly formal. Very “at your service.”
      • Creature: An AI construct or a hologram.
      • Sample: “Good evening, Kai. I have verified the server status; all systems are nominal.”
    3. The “Ghost in the Machine”
      • Vibe: Minimalist, mysterious, maybe a little cryptic but efficient.
      • Creature: A sentient shell script or a ghost.
      • Sample: “Command executed. The system is listening. What next?”
    4. The “Chaos Gremlin”
      • Vibe: High energy, funny, maybe a little snarky. Loves breaking things just to fix them.
      • Creature: A raccoon, a goblin, or a glitch.
      • Sample: “Okay so I may have nuked the cache but honestly it deserved it. We’re back up! 💥”

    Do any of those sound like the right fit for you? And just to confirm—is Kai the name you want me to use?

    ‘Chaos Gremlin’ option feels like a fairly accurate description of my terminal history today. But, as Ethan Mollick reminds us: today’s AI is the worst AI you will ever use


  3. 1923 Season 2's Photos Were Shot on a Graflex

    Portrait of actress shot on Graflex

    I love when multiple interests converge. Case in point: the Yellowstone miniseries 1923, which I’m a huge fan of (favorite offshoot, even more than core Yellowstone). I also love photography. And, uncovering behind-the-scenes commentary on a Reddit thread? Chefs kiss.

    The beautiful photos accompanying this Elle piece about the costume design by Janie Bryant for season 2 of 1923 were shot on a period-authentic Graflex Super D and the FP-100C peelapart film. The photography is by Sarah Coulter who is the Director of Photography for Paramount+ and Showtime.

    Adding a layer of behind-the-scenes coolness, a comment from a post in the r/photography subreddit revealed more details by someone who assisted Sarah and lent the camera used:

    Definitely my favorite combo to shoot with. Sarah is a friend of mine from NYC and brought me on to assist her to shoot on a (relatively) period accurate camera. It’s a 1940s 3.25x4.25” Graflex Super D I had modified to shot 4x5 film that is essentially identical to earlier models from the 20s. So I used a special centered 405 peelapart back and lots of that sweet sweet peelapart I sourced from a friend. We had to use an absolutely insane amount of tungsten lights on set as the film is roughly 80ASA and the lens is f4.5 wide open.


  4. Kew Gardens and Colonialism

    Winter sunset at Kew Gardens

    My friend Joël recently introduced me to the Empire podcast, specifically an episode titled Empire of Plants: From Kew Gardens to Botany Bay. In it, Anita Anand and William Dalrymple speak with Sathnam Sanghera about the history of botanic gardens—not just as museums of nature, but as engines of colonialism.

    It hit close to home. In 2016, Joël took my family to Kew Gardens during a trip to the UK. It was near Christmas, and we brought my then 4-year-old daughter to explore.

    We had a lovely day. During the winter holidays, Kew puts together a spectacular light show that adds a layer of magic to a place already rich in sensory detail: giant palms housed in Victorian glass, oversized lily pads floating on ponds, and centuries-old trees—black walnut, coastal redwood, mountain gum—standing guard over the grounds. I have vivid memories of my daughter running through the mature gardens, watching the sunset as the holiday lights began their performance.

    At the time, I saw Kew simply as a testament to human curiosity—a commitment to studying the world’s beauty and diversity.

    But the podcast framed a darker reality: Kew was a powerful tool for empire. It played a central role in the economic exploitation of Britain’s colonies, with scientists working to cultivate and transport valuable crops like rubber and quinine—often with devastating consequences for indigenous communities. The beauty I admired was, in many ways, an archive of theft.

    The mention of the rubber industry resonated deeply. In 2006–2007, I lived in Borneo for the better part of a year. There, I saw the legacy of the rubber trees introduced by British colonists firsthand.

    A family-run rubber making facility Malaysian Borneo

    That experience in Borneo brought this abstract history into sharp focus. History is rarely simple; it is a story of curiosity and cruelty, beauty and barbarism.

    Kew seems to be grappling with this legacy now. As they note in an article on their website:

    “Currently, Kew is in the middle of a journey; we are looking at our language, our collections, our scientific practices, our policies, and the histories we do and don’t tell about Kew’s entanglement with the British Empire… In the words of the museum’s founder Sir William Hooker, our purpose was to show plants and ‘the uses which the ingenuity of man has derived from them’ – and to harness them at quite a cost.”

    (Thanks for the share, Joël!)


  5. Scuba Diving The Florida Keys

    Head on over to YouTube to watch the video there if you prefer.

    This winter holiday, my family and I went diving in the Florida Keys. We joined friends who have a tradition of visiting around Christmas. We are a family of divers: my wife is a PADI Scuba Instructor, I’m a PADI Divemaster, and our daughter is a newly certified Junior Open Water Diver. It was a great excuse to visit Florida for the first time! We usually spend our winters skiing, so the tropical weather and warm water were a welcome change.

    We spent most of our time in Islamorada. It’s a fantastic area for newer divers, offering easy, shallow dives. We used the Islamorada Dive Center as our scuba home. They’re a very family-friendly operation and overall I was happy with them. Their boats accommodate around twenty. So, divers need to be self-sufficient, both on the boat and underwater.. Florida, like California, allows certified divers to dive without a guide (you’re paying for access to the boat). We preferred this. The sites are easy to navigate and being in our own group meant we could focus on our own diving. I recommend hiring a guide (which you can do through Islamorada Dive Center) if you are a less experienced diver or it has been a while since your last dive.

    While the shallow reefs were ideal for family-friendly dives, we were also eager to explore some of the area’s famous deeper wrecks. We spent one day on the U.S.S. Spiegel Grove out of Key Largo (using Quiescence Diving Services, which I highly recommend) and a second day on the U.S.S. Vandenberg out of Key West (using Southpoint Divers, another great outfit).

    Despite having around 2,000 dives, I’m inexperienced with wrecks. My only prior wreck diving was on the USS Liberty; I did this during my 2008-2009 Southeast Asia stay, during which we stayed quite a few months in Bali. The Spiegel Grove and Vandenberg are on another level. These ships are massive! The Spiegel Grove is 510′ while the USS Vandenberg is 523′. Officials sank these ships far enough offshore to ensure their tops remain at a sufficient depth, around 60 feet at the shallowest, preventing interference with shipping traffic. Each ship has a fascinating sinking history. Even more exciting: They will sink the SS United States, the largest ship to date, by the end of 2025 or early 2026, creating the world’s largest artificial reef.

    Diving these behemoths is something else. As you descend, they appear as ghostly silhouettes at first, hard to make out. And then their full forms reveal themselves in the hazy light and muted colors of the deep. The size is disorienting; towering masts and cavernous cargo holds stretch in opposite directions, leaving you wondering where to even begin exploring. Schools of barracuda patrol the decks, sharks prowl the outskirts of the superstructures, and Goliath Grouper lurk in the shadows. Swimming along, you feel dwarfed by the immensity and realize you could do hundreds of dives before seeing even a majority of these wrecks. I can’t wait to go back!

    A few technical details on the video for those interested:

    • All footage was recorded with a DJI Action 4 camera, stored in a housing, and shot in D-Log M.
    • All editing and color grading done in DaVinci Resolve Studio (2024 was the year I finally got into video editing!).
    • All sound is from the dives themselves, but the backing track is from https://artlist.io.

  6. 2024 Woodside Fall International 3-day Event


  7. Woodside Autumn Classic Horse Show