<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Zach Leatherman</title>
  <subtitle>A web development blog written by @zachleat.</subtitle>
  <link href="https://www.zachleat.com/web/feed/atom.xml" rel="self" />
  <link href="https://www.zachleat.com/" />
  <updated>2026-03-06T06:00:00Z</updated>
  <id>https://www.zachleat.com/</id>
  <author>
    <name>Zach Leatherman</name>
  </author>
  <entry>
    <title>Eleventy is now Build Awesome</title>
    <link href="https://www.zachleat.com/web/build-awesome/" />
    <updated>2026-03-06T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/build-awesome/</id>
    <content type="html">&lt;p&gt;The Eleventy project is taking up the Awesome banner. To support the project, please sign up to &lt;a href=&quot;https://www.kickstarter.com/projects/fontawesome/build-awesome-pro&quot;&gt;get notified when our Kickstarter campaign launches&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>State of the Browser 2026</title>
    <link href="https://www.zachleat.com/web/state-of-the-browser/" />
    <updated>2026-02-28T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/state-of-the-browser/</id>
    <content type="html">&lt;p&gt;This is an event post. My individual talk page is here:&lt;/p&gt;
&lt;script type=&quot;module&quot; src=&quot;https://www.zachleat.com/static/browser-window.js&quot;&gt;&lt;/script&gt;
&lt;div&gt;&lt;browser-window mode=&quot;light&quot; icon url=&quot;https://2026.stateofthebrowser.com/speaker/zach-leatherman/&quot; shadow flush style=&quot;--bw-background: oklch(76.202% 0.1562 84.861)&quot;&gt;&lt;a href=&quot;https://2026.stateofthebrowser.com/speaker/zach-leatherman/&quot; class=&quot;favicon-optout&quot;&gt;&lt;img alt=&quot;Screenshot image for https://2026.stateofthebrowser.com/speaker/zach-leatherman/&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; class=&quot;&quot; src=&quot;https://screenshot.11ty.app/https%3A%2F%2F2026.stateofthebrowser.com%2Fspeaker%2Fzach-leatherman%2F/opengraph/&quot; width=&quot;1200&quot; height=&quot;630&quot;&gt;&lt;/a&gt;&lt;/browser-window&gt;&lt;/div&gt;
&lt;p&gt;Get your tickets while they last!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An Official* Logo for HTML</title>
    <link href="https://www.zachleat.com/web/html-logo/" />
    <updated>2026-02-19T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/html-logo/</id>
    <content type="html">&lt;p&gt;*&lt;em&gt;Not official.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I was working on my slide deck for the &lt;a href=&quot;https://2026.stateofthebrowser.com/&quot;&gt;upcoming State of the Browser conference&lt;/a&gt; and ran into what I would classify as a recurring issue: HTML needs a logo. There isn’t a broadly accepted official logo for (version-independent) HTML. There &lt;em&gt;is&lt;/em&gt; a logo for HTML 5, but that versioned marketing term has long fallen out of regular use (and was introduced 18 years ago).&lt;/p&gt;
&lt;p&gt;This is a community solved problem in both the CSS and JavaScript spaces!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSS: &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fab-fa-css&quot; xlink:href=&quot;#fab-fa-css&quot;&gt;&lt;/use&gt;&lt;/svg&gt;, &lt;a href=&quot;https://github.com/CSS-Next/css-next/issues/105&quot;&gt;relevant discussion on &lt;code&gt;CSS-Next&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;JS: &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fab-fa-js&quot; xlink:href=&quot;#fab-fa-js&quot;&gt;&lt;/use&gt;&lt;/svg&gt;, &lt;a href=&quot;https://github.com/voodootikigod/logo.js&quot;&gt;relevant discussion on &lt;code&gt;voodootikigod/logo.js&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;HTML 5: &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fab-fa-html5&quot; xlink:href=&quot;#fab-fa-html5&quot;&gt;&lt;/use&gt;&lt;/svg&gt;, &lt;a href=&quot;https://www.w3.org/html/logo/&quot;&gt;more info on w3.org&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wish the classic orange badge hadn’t included a version number, but alas.&lt;/p&gt;
&lt;p&gt;Anyway, I very quickly &lt;a href=&quot;https://fediverse.zachleat.com/@zachleat/116093900452223373&quot;&gt;threw my hat into the ring&lt;/a&gt; and immediately recognized a &lt;a href=&quot;https://indieweb.social/@sstephenson/116098428280403793&quot;&gt;much better option from Sam Stephenson&lt;/a&gt; &lt;a href=&quot;https://sls.name/&quot;&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-user&quot; xlink:href=&quot;#fas-fa-user&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;code&gt;sls.name&lt;/code&gt;&lt;/a&gt; that I’ll be considering canon moving forward (and hopefully this blog post puts some weight behind it for others too).&lt;/p&gt;
&lt;p&gt;Here’s what it looks like rendered in your web browser:&lt;/p&gt;
&lt;div class=&quot;flex flex-center&quot;&gt;&lt;a href=&quot;https://indieweb.social/@sstephenson/116098428280403793&quot; style=&quot;all:initial;cursor:pointer;font-size:2rem;width:4em;height:4em;color:blue;text-decoration:underline;display:flex;align-items:center;justify-content:center;background:#ccc;border:.5em outset #aaa;font-weight:900;&quot;&gt;HTML&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I love the nod to the classic unvisited link color and the heavy outset border that doubles as angle brackets with the right head tilt.&lt;/p&gt;
&lt;p&gt;If you’re interested in the source code, the HTML-only (copy-paste friendly) source code is included below &lt;a href=&quot;https://codepen.io/zachleat/pen/azZggqZ&quot;&gt;&lt;em&gt;(and also on Codepen)&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://indieweb.social/@sstephenson/116098428280403793&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;initial&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;4em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;4em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;blue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;text-decoration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;underline&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;#ccc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;.5em outset #aaa&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;900&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;HTML&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>How Eleventy Survived: Funding, Growth, and Open Source Reality</title>
    <link href="https://www.zachleat.com/web/podcast-awesome-eleventy-open-source/" />
    <updated>2026-02-03T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/podcast-awesome-eleventy-open-source/</id>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Eleventy started as a side project. Now it’s a critical infrastructure for thousands of websites.&lt;/p&gt;
&lt;p&gt;TL;DR: Open source isn’t broken. But the way we fund it often is. Let’s talk about what actually works.&lt;/p&gt;
&lt;p&gt;In this episode, we sit down with Zach Leatherman, creator of Eleventy (11ty), to talk honestly about what happens after open source succeeds. From nap-time coding and nights-and-weekends maintenance to venture capital pressure, burnout risk, and the reality of funding long-lived developer tools, this conversation digs into the cultural and financial tradeoffs behind modern open source.&lt;/p&gt;
&lt;p&gt;We cover sustainability, community expectations, funding models that don’t rely on hockey-stick growth, and why “free forever” only works if the people behind the project can stay whole humans.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Listen in: &lt;a href=&quot;https://www.podcastawesome.com/2092855/episodes/18615318-how-eleventy-survived-funding-growth-and-open-source-reality&quot;&gt;How Eleventy Survived: Funding, Growth, and Open Source Reality&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Also on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=GrLHE5djtPA&quot;&gt;YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://overcast.fm/+AA-SZeh8B8A&quot;&gt;Overcast.fm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/us/podcast/how-eleventy-survived-funding-growth-and-open-source/id1660959088?i=1000747878278&quot;&gt;Apple Podcasts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Eleventy, 2025 in Review</title>
    <link href="https://www.zachleat.com/web/eleventy-2025-review/" />
    <updated>2026-01-12T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/eleventy-2025-review/</id>
    <content type="html">&lt;p&gt;A look back at the &lt;a href=&quot;https://www.11ty.dev/blog/review-2025/&quot;&gt;2025 highlights for the 11ty org and the Eleventy project&lt;/a&gt;!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It was another huge year for 11ty. We shipped 177 releases (73% more than 2024) across the full 11ty/* suite. We closed 804 issues (15% more than 2024). We reduced core’s dependency count by 28% and weight by 22%. More folks are building with Eleventy than ever: our year-over-year npm downloads (for only core) are up by 51%!&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  <entry>
    <title>No more tokens! Locking down npm Publish Workflows</title>
    <link href="https://www.zachleat.com/web/npm-security/" />
    <updated>2025-12-04T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/npm-security/</id>
    <content type="html">&lt;p&gt;With the recent spate of high profile npm security incidents involving compromised deployment workflows, I decided that it would be prudent to do a full inventory of my npm security footprint (especially for &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Just in the last few months:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;November 2025&lt;/code&gt;: &lt;a href=&quot;https://socket.dev/blog/shai-hulud-strikes-again-v2&quot;&gt;Shai Halud v2 (PostHog)&lt;/a&gt; (and &lt;a href=&quot;https://posthog.com/blog/nov-24-shai-hulud-attack-post-mortem&quot;&gt;PostHog post-mortem&lt;/a&gt;): Worm infected ×834 packages. Propagated via &lt;code&gt;preinstall&lt;/code&gt; npm script.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;September 2025&lt;/code&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/tinycolor-supply-chain-attack-affects-40-packages&quot;&gt;Shai Halud (&lt;code&gt;@ctrl/tinycolor&lt;/code&gt;, CrowdStrike)&lt;/a&gt;: Worm infected ×526 packages. Propagated via &lt;code&gt;postinstall&lt;/code&gt; npm script.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/duckdb-npm-account-compromised-in-continuing-supply-chain-attack&quot;&gt;DuckDB&lt;/a&gt;: targeted phishing email (&lt;em&gt;with&lt;/em&gt; 2FA) pointed to fake domain &lt;code&gt;npmjs.help&lt;/code&gt;. Compromised packages were published with token created by attacker.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/npm-author-qix-compromised-in-major-supply-chain-attack&quot;&gt;&lt;code&gt;debug&lt;/code&gt; and &lt;code&gt;chalk&lt;/code&gt;&lt;/a&gt;: same as above: targeted phishing email (&lt;em&gt;with&lt;/em&gt; 2FA).&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;August 2025&lt;/code&gt;: &lt;a href=&quot;https://socket.dev/blog/nx-packages-compromised&quot;&gt;S1ngularity (Nx)&lt;/a&gt; (and &lt;a href=&quot;https://nx.dev/blog/s1ngularity-postmortem&quot;&gt;Nx post-mortem&lt;/a&gt;): well-meaning but insecure code (from approved authors) was merged which allowed arbitrary commands to be executed via content in Pull Requests to the repo. Compromised packages were published via a stolen NPM token.&lt;/li&gt;
&lt;/ul&gt;
&lt;details&gt;
&lt;summary&gt;Expand to see the insecure YAML from the S1ngularity attack &lt;!-- https://github.com/nrwl/nx/pull/32458/files --&gt;&lt;/summary&gt;
&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Some content omitted for brevity&lt;/span&gt;
on:
  pull_request:
    types: &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;opened, edited, synchronize, reopened&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;# …&lt;/span&gt;
jobs:
  validate-pr-title:
    &lt;span class=&quot;token comment&quot;&gt;# …&lt;/span&gt;
    steps:
      &lt;span class=&quot;token comment&quot;&gt;# …&lt;/span&gt;
      - name: Create PR message &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;
        run: &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; /tmp
          &lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /tmp/pr-message.txt &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;EOF&#39;&lt;/span&gt;
          &lt;span class=&quot;token variable&quot;&gt;${{ github.event.pull_request.title }&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

          &lt;span class=&quot;token variable&quot;&gt;${{ github.event.pull_request.body }&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          EOF

      - name: Validate PR title
        run: &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Validating PR title: &lt;span class=&quot;token variable&quot;&gt;${{ github.event.pull_request.title }&lt;/span&gt;}&quot;&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; ./scripts/commit-lint.js /tmp/pr-message.txt&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;Given the attack vectors of recent incidents, any packages using GitHub Actions (or other CI) to publish should be considered to have an elevated risk (and this was very common across &lt;a href=&quot;https://github.com/orgs/11ty/repositories&quot;&gt;&lt;code&gt;11ty&lt;/code&gt;’s &lt;em&gt;numerous&lt;/em&gt; packages&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I’ve been pretty cautious about npm tokens. I have each repository set up (painstakingly) to use &lt;em&gt;extremely&lt;/em&gt; granular tokens (access to publish one package and one package &lt;em&gt;only&lt;/em&gt;). This limits the blast radius of any compromise to a single package and has helped manage my blood pressure (I accidentally &lt;a href=&quot;https://github.com/11ty/eleventy-plugin-syntaxhighlight/issues/93&quot;&gt;leaked&lt;/a&gt; a token earlier this year).&lt;/p&gt;
&lt;h2 id=&quot;security-checklist&quot;&gt;Security Checklist&lt;/h2&gt;
&lt;p&gt;I’ve completed my review and made a bunch of changes to improve my security footprint on GitHub and npm, noted below. The suggestions below avoid introducing additional third-party tooling that may decrease your footprint short-term (while actually increasing it long-term).&lt;/p&gt;
&lt;p&gt;Caveat: my current workflow uses GitHub Releases to trigger a GitHub Action workflow to publish packages to npm (and this advice may vary a bit if you’re using different tools like GitLab or pnpm or yarn, sorry).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-check-double&quot; xlink:href=&quot;#fas-fa-check-double&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;Two-Factor Authentication&lt;/strong&gt; (2FA) for both GitHub AND npm, for &lt;em&gt;every&lt;/em&gt; person that has access to publish. This is table-stakes. No compromises. Require 2FA everywhere.
&lt;ul&gt;
&lt;li&gt;On GitHub, go to your organization’s Settings page and navigate to Authentication Security. Check the &lt;em&gt;Require Two-factor authentication for everyone&lt;/em&gt; and &lt;em&gt;Only allow secure two-factor methods&lt;/em&gt; checkboxes.&lt;/li&gt;
&lt;li&gt;npm requires you to specify this on a per-package basis that I describe in the &lt;em&gt;Restrict Publishing Access&lt;/em&gt; section below.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When logging into npm and GitHub, use your &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-key&quot; xlink:href=&quot;#fas-fa-key&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;password manager exclusively&lt;/strong&gt;! Never type in a password or a 2FA code manually. Your password manager will help ensure that you don’t put in your credentials on a compromised (but realistic looking) domain.
&lt;ul&gt;
&lt;li&gt;Would you know that &lt;code&gt;npmjs.help&lt;/code&gt; was a spoofed domain? Maybe on your average day, but on your worst day? When you didn’t sleep well the night before? 😴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Review GitHub users that have the &lt;a href=&quot;https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/managing-repository-roles/repository-roles-for-an-organization#permissions-for-each-role&quot;&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-pencil&quot; xlink:href=&quot;#fas-fa-pencil&quot;&gt;&lt;/use&gt;&lt;/svg&gt;Write role&lt;/a&gt; in your repositories (Write can create releases).&lt;/li&gt;
&lt;li&gt;Find any repositories using NPM tokens and &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-skull&quot; xlink:href=&quot;#fas-fa-skull&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;delete the tokens&lt;/strong&gt; in the settings for &lt;em&gt;both&lt;/em&gt; GitHub and npm. We’re moving to a post-token world.
&lt;ul&gt;
&lt;li&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-trophy&quot; xlink:href=&quot;#fas-fa-trophy&quot;&gt;&lt;/use&gt;&lt;/svg&gt;Success criteria is having &lt;a href=&quot;https://fediverse.zachleat.com/@zachleat/115652337081660540&quot;&gt;0 Access Tokens listed in your npm Settings&lt;/a&gt; (granular or otherwise).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Switch to use &lt;a href=&quot;https://docs.npmjs.com/trusted-publishers&quot;&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-plug&quot; xlink:href=&quot;#fas-fa-plug&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;Trusted Publishers&lt;/strong&gt;&lt;/a&gt; (OIDC) in the Settings tab for each npm package. This will also setup the release to include provenance as well (which is great).
&lt;ul&gt;
&lt;li&gt;This scopes your credentials to one specific GitHub Action (you specify which file to point to in &lt;code&gt;.github/workflows/&lt;/code&gt;) and allows you to remove any references to tokens in the GitHub Actions YAML configuration file.&lt;/li&gt;
&lt;li&gt;The big goal here for me was to completely separate my publish workflow and credentials and disallow any access to those credentials from other workflows in the repository (usually unit tests that run on every commit to the repo). You &lt;em&gt;could&lt;/em&gt; also use GitHub Environments to achieve this. This limits the blast radius from worm propagation (via &lt;code&gt;postinstall&lt;/code&gt; or &lt;code&gt;preinstall&lt;/code&gt;) to publish events only (not every commit), which is far more infrequent.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restrict npm Publishing Access&lt;/strong&gt; in the Settings tab for each npm package. Use the &lt;em&gt;Require two-factor authentication and disallow tokens (recommended)&lt;/em&gt; option. Death to tokens!&lt;/li&gt;
&lt;li&gt;Check in your &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-lock&quot; xlink:href=&quot;#fas-fa-lock&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;lock file&lt;/strong&gt; (e.g. &lt;code&gt;package-lock.json&lt;/code&gt; for npm). This is especially important when using a release script that uses npm packages to generate release artifacts. Use &lt;a href=&quot;https://docs.npmjs.com/cli/v10/commands/npm-ci&quot;&gt;&lt;code&gt;npm ci&lt;/code&gt;&lt;/a&gt; instead of &lt;code&gt;npm install&lt;/code&gt; in your release script.&lt;/li&gt;
&lt;li&gt;GitHub Actions configuration files should &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-thumbtack&quot; xlink:href=&quot;#fas-fa-thumbtack&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;strong&gt;pin the full SHA&lt;/strong&gt; for &lt;code&gt;uses&lt;/code&gt; dependencies (e.g. &lt;a href=&quot;https://github.com/11ty/eleventy-plugin-vite/blob/c04e9630b8c89a9ca8896eb0ab35328323d99ee1/.github/workflows/release.yml#L14-L15&quot;&gt;&lt;code&gt;eleventy-plugin-vite&lt;/code&gt;&lt;/a&gt;). I learned that &lt;a href=&quot;https://github.com/11ty/eleventy-plugin-vite/blob/c04e9630b8c89a9ca8896eb0ab35328323d99ee1/.github/dependabot.yml#L9&quot;&gt;Dependabot can update and manage these&lt;/a&gt; too!&lt;!-- I’m reminded of my [`setup-node` dependency failing on Node 22](https://fediverse.zachleat.com/@zachleat/112814100573630319) last year (though I couldn’t say conclusively whether or not this would have avoided that issue). --&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;other-good-ideas&quot;&gt;Other good ideas&lt;/h3&gt;
&lt;p&gt;Given the above changes, I would consider the following items to not to be of immediate urgency (though still recommended).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub: Enable &lt;a href=&quot;https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/immutable-releases&quot;&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-house-lock&quot; xlink:href=&quot;#fas-fa-house-lock&quot;&gt;&lt;/use&gt;&lt;/svg&gt;Immutable Releases&lt;/a&gt; preferably at the organization level. This will ensure no one can change tags and release contents after a release has been shipped.&lt;/li&gt;
&lt;li&gt;Use a package manager &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-snowflake&quot; xlink:href=&quot;#fas-fa-snowflake&quot;&gt;&lt;/use&gt;&lt;/svg&gt;cooldown.
&lt;ul&gt;
&lt;li&gt;Added the &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#cooldown-&quot;&gt;&lt;code&gt;cooldown&lt;/code&gt; option to my Dependabot configuration&lt;/a&gt; (direct &lt;a href=&quot;https://github.com/11ty/eleventy/blob/bcd75f56524a3874aeb3dfb49569ffd5ac745ca5/.github/dependabot.yml#L12-L13&quot;&gt;link to &lt;code&gt;dependabot.yml&lt;/code&gt;&lt;/a&gt;). This updates production dependencies weekly, now with a 7 day cooldown.&lt;/li&gt;
&lt;li&gt;I usually use &lt;code&gt;npm-check-updates&lt;/code&gt; for local package.json file maintenance. It has a &lt;a href=&quot;https://github.com/raineorshine/npm-check-updates?tab=readme-ov-file#cooldown&quot;&gt;&lt;code&gt;cooldown&lt;/code&gt; option too&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm install&lt;/code&gt; does have a &lt;a href=&quot;https://docs.npmjs.com/cli/v11/commands/npm-install#before&quot;&gt;&lt;code&gt;--before&lt;/code&gt;&lt;/a&gt; option to pass a Date that can be used similarly (though isn’t &lt;a href=&quot;https://github.com/npm/cli/pull/8802&quot;&gt;relative&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;More on &lt;a href=&quot;https://socket.dev/blog/pnpm-10-16-adds-new-setting-for-delayed-dependency-updates&quot;&gt;socket.dev: pnpm 10.16 Adds New Setting for Delayed Dependency Updates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Reduce &lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fas-fa-arrow-down&quot; xlink:href=&quot;#fas-fa-arrow-down&quot;&gt;&lt;/use&gt;&lt;/svg&gt;dependencies! Every third party dependency has some risk associated with it, as you’re inheriting a bit of those developers’ security footprint too. It’s worth noting that the work being done by the folks at &lt;a href=&quot;https://e18e.dev/&quot;&gt;e18e&lt;/a&gt; to reduce dependency counts is making great headway to improve the ecosystem at large. You can do this in your own projects! I’m proud of the work we’ve done on &lt;code&gt;@11ty/eleventy&lt;/code&gt; over the years (source: &lt;a href=&quot;https://github.com/11ty/eleventy/releases/tag/v3.1.0&quot;&gt;v3.1.0 release notes&lt;/a&gt;): &lt;table&gt;&lt;thead&gt;
  &lt;tr&gt;
    &lt;th&gt;Version&lt;/th&gt;
    &lt;th&gt;Production Dep Count&lt;/th&gt;
    &lt;th&gt;Production Size&lt;/th&gt;
  &lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
  &lt;tr&gt;
    &lt;td&gt;v3.1.0&lt;/td&gt;
    &lt;td&gt;×142&lt;/td&gt;
    &lt;td&gt;21.4 MB&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;v3.0.0&lt;/td&gt;
    &lt;td&gt;×187&lt;/td&gt;
    &lt;td&gt;27.4 MB&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;v2.0.1&lt;/td&gt;
    &lt;td&gt;×215&lt;/td&gt;
    &lt;td&gt;36.4 MB&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;v1.0.2&lt;/td&gt;
    &lt;td&gt;×356&lt;/td&gt;
    &lt;td&gt;73.3 MB&lt;/td&gt;
  &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;Some folks recommend disabling scripts when installing (via &lt;code&gt;npm config set ignore-scripts true&lt;/code&gt; or via stock use of &lt;a href=&quot;https://pnpm.io/&quot;&gt;pnpm&lt;/a&gt;). This might be marginally useful in some cases but in my opinion is just a short term solution in response to common attack patterns that we’ve already seen. Importing (or requiring) a compromised or malicious package can execute arbitrary commands without using a &lt;code&gt;preinstall&lt;/code&gt; or &lt;code&gt;postinstall&lt;/code&gt; script just fine. If you really need to lock down your environment, you might consider running a &lt;a href=&quot;https://www.virtualbox.org/&quot;&gt;Virtual Machine&lt;/a&gt;, &lt;a href=&quot;https://code.visualstudio.com/docs/devcontainers/create-dev-container&quot;&gt;Dev Container&lt;/a&gt;, and/or using &lt;a href=&quot;https://nodejs.org/docs/latest/api/permissions.html&quot;&gt;Node.js’ Permissions model&lt;/a&gt; or &lt;a href=&quot;https://docs.deno.com/runtime/fundamentals/security/&quot;&gt;stock Deno&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stay safe out there, y’all!&lt;/p&gt;
&lt;h2 id=&quot;additional-reading&quot;&gt;Additional Reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://snyk.io/articles/npm-security-best-practices-shai-hulud-attack/&quot;&gt;snyk NPM Security Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openjsf.org/blog/publishing-securely-on-npm&quot;&gt;Publishing More Securely on npm: Guidance from the OpenJS Security Collaboration Space&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/npm-pub-2025/ci-publish&quot;&gt;Publishing from CI with 2FA (GitHub Tutorial)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>How to Hallucinate using Web Components</title>
    <link href="https://www.zachleat.com/web/hallucinate/" />
    <updated>2025-11-21T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/hallucinate/</id>
    <content type="html">&lt;p&gt;Say, you want the smooth convenience of consuming content that &lt;em&gt;feels&lt;/em&gt; like it’s generated in real time &lt;em&gt;without&lt;/em&gt; having to deal with the tradeoffs of a Large Language Model née Artificial Intelligence.&lt;/p&gt;
&lt;p&gt;Why not use animation? It’s the perfect metaphor for a Hollywood-esque veneer of complexity without substance, in no way similar to how an entire industry is currently being oversold and at no risk of imminent collapse.&lt;/p&gt;
&lt;p&gt;This approach animates each blog post’s content (already generated by a human, manually) progressively to emulate existing chatbox user experience patterns for hallucinating text. You can try it out right now by hitting the &lt;em&gt;Hallucinate&lt;/em&gt; toggle below:&lt;is-land on:media=&quot;(prefers-reduced-motion: no-preference)&quot;&gt;
&lt;template data-island&gt;
&lt;is-land on:visible class=&quot;toggle-island&quot;&gt;&lt;/is-land&gt;&lt;/template&gt;&lt;/is-land&gt;&lt;/p&gt;
&lt;p&gt;&lt;button id=&quot;ai-mode-inline&quot; type=&quot;button&quot; aria-pressed=&quot;false&quot; class=&quot;toggle&quot;&gt;
&lt;span class=&quot;toggle-control&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;toggle-text&quot;&gt;Hallucinate&lt;/span&gt;
&lt;/button&gt;
&lt;template data-island=&quot;once&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;https://www.zachleat.com/static/toggle-button.css&quot;&gt;
&lt;script src=&quot;https://www.zachleat.com/static/toggle-button.js&quot;&gt;&lt;/script&gt;
&lt;/template&gt;


&lt;/p&gt;
&lt;h2 id=&quot;how-does-it-work&quot;&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;This makes use of the &lt;a href=&quot;https://www.zachleat.com/web/squirminal/&quot;&gt;&lt;code&gt;&amp;lt;squirm-inal&amp;gt;&lt;/code&gt; Web Component&lt;/a&gt;, originally for &lt;a href=&quot;https://your-year-on.netlify.com/&quot;&gt;Netlify’s Your Year on Netlify&lt;/a&gt; microsite and using lessons learned from &lt;a href=&quot;https://www.zachleat.com/web/queue-code/&quot;&gt;Queue Code (a way to live code without live coding)&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// It works with any arbitrary HTML content&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// including this syntax highlighted code block&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&quot;use AI&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To implement this yourself, just wrap any arbitrary content (say &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;) in a newly created &lt;code&gt;&amp;lt;squirm-inal autoplay speed=&amp;quot;0.6&amp;quot;&amp;gt;&lt;/code&gt; element and you’re off to the races.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://unpkg.com/@zachleat/squirminal@3.0.1/squirminal.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;integrity&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;sha384-m+pplzdzdfZuwjyxmM9pOkp/ALfMMjZll/b2g2mR6mhurvj1ZZAe8xXNj7BSp4XM&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
	&lt;span class=&quot;token attr-name&quot;&gt;crossorigin&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;anonymous&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; main &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; squirm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;squirm-inal&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
squirm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;speed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.6&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
squirm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;autoplay&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
squirm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;children&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;squirm&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;You could swap the &lt;code&gt;&amp;lt;script src&amp;gt;&lt;/code&gt; above to use &lt;code&gt;import()&lt;/code&gt; instead but that would remove the option for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity&quot;&gt;subresource &lt;code&gt;integrity&lt;/code&gt;&lt;/a&gt; (always important for CDN use).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That’s it!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How we use GitHub Issues (on 11ty) and how that’s Changing</title>
    <link href="https://www.zachleat.com/web/11ty-github-issues/" />
    <updated>2025-11-03T06:00:00Z</updated>
    <id>https://www.zachleat.com/web/11ty-github-issues/</id>
    <content type="html"></content>
  </entry>
  <entry>
    <title>Copy *and* Paste? …in this Economy?</title>
    <link href="https://www.zachleat.com/web/copy-paste/" />
    <updated>2025-10-28T05:00:00Z</updated>
    <id>https://www.zachleat.com/web/copy-paste/</id>
    <content type="html">&lt;p&gt;Astute visitors to the &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;Eleventy Documentation&lt;/a&gt; will notice something new on the code blocks on the site.&lt;/p&gt;
&lt;style&gt;
#demo-fa-copy-button {
	wa-copy-button { line-height: 1; vertical-align: text-bottom; }
	wa-copy-button::part(button) { padding: 0; }
	wa-copy-button::part(copy-icon),
	wa-copy-button::part(success-icon),
	wa-copy-button::part(error-icon) { font-size: 1.3125em;  }
}
&lt;/style&gt;
&lt;div id=&quot;demo-fa-copy-button&quot;&gt;&lt;p&gt;&lt;em&gt;A wild copy-to-clipboard component has appeared: &lt;wa-copy-button tooltip-placement=&quot;right&quot; value=&quot;Unparalleled synergy&quot;&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#far-fa-copy&quot; xlink:href=&quot;#far-fa-copy&quot;&gt;&lt;/use&gt;&lt;/svg&gt;&lt;/wa-copy-button&gt;&lt;/em&gt;&lt;/p&gt;&lt;/div&gt;
&lt;p&gt;This feature been a &lt;em&gt;long&lt;/em&gt; time coming and is our first use of &lt;a href=&quot;https://webawesome.com/&quot;&gt;&lt;svg class=&quot;z-icon&quot; width=&quot;20&quot; height=&quot;20&quot;&gt;&lt;use href=&quot;#fab-fa-web-awesome&quot; xlink:href=&quot;#fab-fa-web-awesome&quot;&gt;&lt;/use&gt;&lt;/svg&gt;Web Awesome&lt;/a&gt; on the docs (via the &lt;a href=&quot;https://webawesome.com/docs/components/copy-button/&quot;&gt;&lt;code&gt;&amp;lt;wa-copy-button&amp;gt;&lt;/code&gt; custom element&lt;/a&gt;). Take special note of the unparalleled &lt;em&gt;synergy&lt;/em&gt; of the Font Awesome icon used by the Web Awesome component used on the &lt;em&gt;Eleventy&lt;/em&gt; docs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Progressive Enhancement behavior: this is a JavaScript-only feature and has no before/without JavaScript experience. You might call this a &lt;a href=&quot;https://www.zachleat.com/web/a-taxonomy-of-web-component-types/#javascript-web-components&quot;&gt;JavaScript Web Component&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Performance-focused:
&lt;ul&gt;
&lt;li&gt;This is using a &lt;a href=&quot;https://github.com/11ty/11ty-website/blob/afd92d6f44332323eda33a9380d5e3979074b497/eleventy.config.js#L479&quot;&gt;build-time component bundle&lt;/a&gt; (read more about Bundling below)&lt;/li&gt;
&lt;li&gt;The JavaScript code for the component only loads when an instance is visible (via &lt;a href=&quot;https://www.11ty.dev/docs/plugins/is-land/&quot;&gt;&lt;code&gt;&amp;lt;is-land&amp;gt;&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;
&lt;h3 id=&quot;direct-from-cdn&quot;&gt;Direct from CDN&lt;/h3&gt;
&lt;p&gt;There are a few ways to use the Copy Button component stock, with the easiest being to load the script directly from the CDN, like so (via &lt;a href=&quot;https://www.jsdelivr.com/&quot;&gt;&lt;code&gt;jsdelivr&lt;/code&gt;&lt;/a&gt;):&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://cdn.jsdelivr.net/npm/@awesome.me/webawesome@3.0.0/dist-cdn/components/copy-button/copy-button.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or via &lt;a href=&quot;https://www.jsdelivr.com/&quot;&gt;&lt;code&gt;unpkg&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://unpkg.com/@awesome.me/webawesome@3.0.0/dist-cdn/components/copy-button/copy-button.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;bundling&quot;&gt;Bundling&lt;/h3&gt;
&lt;p&gt;For this implementation we used &lt;code&gt;esbuild&lt;/code&gt; to create a focused bundle for the single Web Awesome component (though this &lt;code&gt;esbuild&lt;/code&gt; code would work for any JavaScript file).&lt;/p&gt;
&lt;p&gt;We went with this method for improved runtime performance and to reduce the number of third-party dependencies on the web site (with a nod to &lt;a href=&quot;https://jaenis.ch/&quot;&gt;André Jaenisch&lt;/a&gt;). You can do the same with the following bit of &lt;a href=&quot;https://www.11ty.dev/docs/config/&quot;&gt;Eleventy configuration&lt;/a&gt; (e.g. in a &lt;code&gt;eleventy.config.js&lt;/code&gt; file):&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// eleventy.config.js&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// don’t forget to `npm install esbuild -D`&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; esbuild &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;esbuild&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; fileURLToPath &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;node:url&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;esbuildToFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;entryPoints&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outfile&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; esbuild&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		entryPoints&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;browser&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;esm&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;bundle&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;minify&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;banner&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token literal-property property&quot;&gt;js&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/* via &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;entryPoints&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; */&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		outfile&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bundleModuleToFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;modulePath&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outfile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; sourcefile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fileURLToPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;meta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;modulePath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;esbuildToFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; sourcefile &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outfile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; outfile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;directories&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;output&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;js/copy-button.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// This will run once per build/serve/watch&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// (not with subsequent builds, save for config file changes)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bundleModuleToFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@awesome.me/webawesome/dist/components/copy-button/copy-button.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outfile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;markdown-code-block-wrappers&quot;&gt;Markdown Code Block Wrappers&lt;/h2&gt;
&lt;p&gt;This task also served as the impetus for fixes related to &lt;a href=&quot;https://www.zachleat.com/web/markdown-code-wrapper/&quot;&gt;wrapper elements around code blocks in Markdown&lt;/a&gt;, documented in a previous blog post on this very web site.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Permanent Facepile Credit to Individuals Supporting Eleventy</title>
    <link href="https://www.zachleat.com/web/permanent-eleventy-facepile/" />
    <updated>2025-10-22T05:00:00Z</updated>
    <id>https://www.zachleat.com/web/permanent-eleventy-facepile/</id>
    <content type="html">&lt;p&gt;Every single page of the 11ty.dev Docs has a &lt;a href=&quot;https://www.11ty.dev/#gold-sponsors&quot;&gt;facepile in the footer&lt;/a&gt;, populated (automatically) by our &lt;a href=&quot;https://opencollective.com/11ty&quot;&gt;Open Collective supporters list&lt;/a&gt;. Historically, to be a part of this facepile you needed to meet the following criteria:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Have an &lt;em&gt;active&lt;/em&gt; recurring (monthly/yearly) Open Collective contribution (of any amount).&lt;/li&gt;
&lt;li&gt;Have a non-default avatar or a web site added to your Open Collective profile that &lt;a href=&quot;https://www.11ty.dev/docs/services/indieweb-avatar/&quot;&gt;we can pull a favicon from&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Gold and silver tiers are shuffled randomly at build time but the Supporter tier is sorted by cumulative donation amount (descending).&lt;/p&gt;
&lt;p&gt;Moving forward, the Gold and Silver tiers will still require &lt;em&gt;active&lt;/em&gt; contributions but we’re relaxing the Supporter tier to be more inclusive of emeritus/former supporters:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Individuals contributing no longer need to be &lt;em&gt;active&lt;/em&gt; and will be shown if cumulative contributions are greater than USD $55. This change means that one-time/non-recurring contributors will now be shown (if the amount meets stated minimums).
&lt;ul&gt;
&lt;li&gt;Organization accounts will still need to have an &lt;em&gt;active&lt;/em&gt; contribution to be shown. &lt;em&gt;(Individual versus organization refers to the &lt;a href=&quot;https://documentation.opencollective.com/getting-started/creating-an-organization&quot;&gt;type of Open Collective account&lt;/a&gt; making the contribution)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you have the default avatar (and no web site in your Open Collective profile) we will now show your entry in the facepile but the minimum cumulative total is USD $200 to use the default avatar. Too many folks don’t have an avatar or web site 😅 which makes the facepile look… well, not great. If you update your profile we will pick up your changes! The build runs (at minimum) daily.&lt;/li&gt;
&lt;li&gt;Notably, it’s unchanged that there are no minimums for &lt;em&gt;active&lt;/em&gt; recurring monthly/yearly contributions (for both individuals and organizations).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I hope this relaxation gives proper &lt;em&gt;permanent&lt;/em&gt; credit to individuals that have contributed monetarily to the project, while filtering out the spam/bot accounts that have contributed a few dollars and subsequently immediately cancelled (hoping to be listed on the web site).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;While I have y’all here I might also mention that your avatar links directly to the web site listed in your Open Collective profile. While these links do &lt;a href=&quot;https://developers.google.com/search/docs/crawling-indexing/qualify-outbound-links&quot;&gt;use &lt;code&gt;rel=&amp;quot;sponsored&amp;quot;&lt;/code&gt;&lt;/a&gt;, it can help your search engine rank so it helps to configure your Open Collective profile appropriately!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Appreciate y’all!&lt;/p&gt;
</content>
  </entry>
</feed>