<?xml version="1.0" encoding="utf-8"?>
  <feed xmlns="http://www.w3.org/2005/Atom">
    <title>damien.zone</title>
    <id>https://damien.zone/feed.xml</id>
    <link href="https://damien.zone/feed.xml" rel="self"/>
    <link href="https://damien.zone/feed.xml" rel="alternate" type="text/html" />
    <icon>https://damien.zone/favicon-bg.png</icon>
    <updated>2026-03-15T14:46:32Z</updated>
    
        <entry>
          <title>&#x201C;This Is Not The Computer For You&#x201D;</title>
          <link href="https://samhenri.gold/blog/20260312-this-is-not-the-computer-for-you/" rel="alternate"/>
          <id>https://samhenri.gold/blog/20260312-this-is-not-the-computer-for-you/</id>
          <published>2026-03-15T14:46:32Z</published>
          <updated>2026-03-15T15:47:40Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;blockquote&#x3E;
&#x3C;p&#x3E;That is not a bug in how he&#x2019;s using the computer. That is the entire mechanism by which a kid becomes a developer. Or a designer. Or a filmmaker. Or whatever it is that comes after spending thousands of hours alone in a room with a machine that was never quite right for what you were asking of it.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;I resonated more with that piece than I expected because, frankly, I &#x3C;em&#x3E;was&#x3C;/em&#x3E; that kid who obsessed with Apple computers before getting my first iMac circa 2009.&#x3C;br /&#x3E;
Maybe if I had been born 20 years later, I would be that kid who lusts after the MacBook Neo because he feels limited by Chromebooks, who knows.&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://samhenri.gold/blog/20260312-this-is-not-the-computer-for-you/&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>macOS Tahoe forced me to abandon Music.app</title>
          <link href="https://damien.zone/macos-tahoe-forced-me-to-abandon-musicapp" rel="alternate"/>
          <id>https://damien.zone/macos-tahoe-forced-me-to-abandon-musicapp</id>
          <published>2026-03-13T02:07:32Z</published>
          <updated>2026-03-14T00:15:18Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;I&#x27;ve been meaning to write this post for &#x3C;em&#x3E;checks notes&#x3C;/em&#x3E; months but, life got in the way, you know how it is.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Those who know me know that I listen to &#x3C;a href=&#x22;https://listenbrainz.org/user/Eramdam/&#x22;&#x3E;&#x3C;em&#x3E;a lot&#x3C;/em&#x3E;&#x3C;/a&#x3E; of music, it&#x27;s the one thing that has been consistent for...uh...most of my life at this point? I started maintaining a music library back when Windows Media Player on Windows XP was &#x3C;em&#x3E;the&#x3C;/em&#x3E; shit, then like everyone else at the time, I found out about WinAmp. Then I started using iTunes, I &#x3C;em&#x3E;think&#x3C;/em&#x3E; I used it before getting a &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/IPod_Nano#/media/File:KoolgiyBlackNano.JPG&#x22;&#x3E;1st gen iPod Nano&#x3C;/a&#x3E; but frankly it has been so long I cannot remember exactly.&#x3C;/p&#x3E;
&#x3C;p&#x3E;All that is to say, I&#x27;ve been collecting music files and organizing them through various means for a while. I endured through iTunes&#x27; idiosyncrasies for essentially most of my time with it, I put up with its weird quirks around music tag management. And I did the same when it transformed into Music.app on macOS.&#x3C;/p&#x3E;
&#x3C;p&#x3E;At some point (circa 2015), I got fed up with having to re-tag stuff by hand and started using &#x3C;a href=&#x22;https://beets.readthedocs.io/en/stable/&#x22;&#x3E;beets&#x3C;/a&#x3E; to manage and tag my music library. It clearly wasn&#x27;t &#x3C;em&#x3E;meant&#x3C;/em&#x3E; to be used in tandem with iTunes/Music.app but I made it work somewhat okay.&#x3C;/p&#x3E;
&#x3C;p&#x3E;That lasted for a while, my library continued to grow, I briefly played around with &#x3C;a href=&#x22;https://www.musicpd.org/&#x22;&#x3E;mpd&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://github.com/ncmpcpp/ncmpcpp&#x22;&#x3E;ncmpcpp&#x3C;/a&#x3E;, but quickly went back to Music.app because I actually liked its UI a lot, despite it evolving sometimes for the worse.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Fast forward to last November when I finally decided to install macOS Tahoe on my main Mac. The upgrade was relatively painless despite... Liquid Glass being a thing. I don&#x27;t &#x3C;em&#x3E;hate&#x3C;/em&#x3E; Liquid Glass on iOS/iPadOS but it is clear it&#x27;s half-assed on the Mac and &#x3C;a href=&#x22;https://sixcolors.com/post/2026/02/2025reportcard/&#x22;&#x3E;this isn&#x27;t a controversial opinion&#x3C;/a&#x3E;. But whatever, for better or worse, Apple&#x27;s weird redesigns are fine, I got used to it relatively quickly.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Then I opened the Music app. After being, hum, startled by the UI and its...questionable decisions I went on to play some music and realized I had become &#x3C;a href=&#x22;https://xkcd.com/1172/&#x22;&#x3E;Longtimeuser4&#x3C;/a&#x3E; because Music.app broke the way I listen to music. You see, I am the type of sicko who has a lot of music&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E; AND who shuffles all of it...by album&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-2&#x22; id=&#x22;user-content-fnref-2&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;2&#x3C;/a&#x3E;&#x3C;/sup&#x3E;, meaning when I press &#x22;play&#x22;, Music.app would pick a random album to play, play it in order and then play another album.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Except Music.app on macOS Tahoe doesn&#x27;t do that anymore. Actually, no, it does but &#x3C;strong&#x3E;much&#x3C;/strong&#x3E; slower than it used to on macOS Sequoia. How slow? Unbearably slow if you have a lot of songs/albums.&#x3C;/p&#x3E;
&#x3C;blockquote class=&#x22;mastodon-embed&#x22; data-embed-url=&#x22;https://social.erambert.me/@eramdam/115506030628602362/embed&#x22; style=&#x22;background:#FCF8FF;border-radius:8px;border:1px solid #C9C4DA;margin:0;max-width:540px;min-width:270px;overflow:hidden;padding:0&#x22;&#x3E; &#x3C;a href=&#x22;https://social.erambert.me/@eramdam/115506030628602362&#x22; target=&#x22;_blank&#x22; style=&#x22;align-items:center;color:#1C1A25;display:flex;flex-direction:column;font-family:system-ui, -apple-system, BlinkMacSystemFont, &#x27;Segoe UI&#x27;, Oxygen, Ubuntu, Cantarell, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, Roboto, sans-serif;font-size:14px;justify-content:center;letter-spacing:0.25px;line-height:20px;padding:24px;text-decoration:none&#x22;&#x3E;  &#x3C;div style=&#x22;color:#787588;margin-top:16px&#x22;&#x3E;Post by @eramdam@erambert.me&#x3C;/div&#x3E; &#x3C;div style=&#x22;font-weight:500&#x22;&#x3E;View on Mastodon&#x3C;/div&#x3E; &#x3C;/a&#x3E; &#x3C;/blockquote&#x3E; 
&#x3C;p&#x3E;This is running on my M1 Max Mac Studio, not a slow machine but somehow prepping the queue takes upwards of &#x3C;strong&#x3E;four seconds&#x3C;/strong&#x3E; and blocks the entire UI doing so, making the app feel unusable. The same operation was instantaneous on macOS Sequoia. This was a clear regression and there wasn&#x27;t much I could do about it. I also knew &#x3C;a href=&#x22;https://michaelhans.com/eclecticism/2025/09/29/macos-tahoe-music-app-breaks-shuffle/&#x22;&#x3E;I wasn&#x27;t the only one complaining about this&#x3C;/a&#x3E;, so it clearly wasn&#x27;t &#x3C;em&#x3E;just&#x3C;/em&#x3E; me!&#x3C;/p&#x3E;
&#x3C;p&#x3E;Some quick troubleshooting showed that the time spent between clicking &#x22;play&#x22; and music playing was directly correlated to the size of the queue, meaning there&#x27;s some &#x3C;em&#x3E;O(N)&#x3C;/em&#x3E; type shit going on&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-3&#x22; id=&#x22;user-content-fnref-3&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;3&#x3C;/a&#x3E;&#x3C;/sup&#x3E;. A friend of mine who happens to be close-ish to the matter helped me gather evidence that could help draft an internal bug report. I wasn&#x27;t exactly confident this would get addressed quickly, if at all. I&#x27;ll be frankly surprised if this gets fixed in macOS 27.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;exploring-the-alternatives&#x22;&#x3E;Exploring the alternatives&#x3C;/h2&#x3E;
&#x3C;p&#x3E;Keep in mind that my set of requirements for a possible solution were fairly picky, I wanted:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;Local music files.
&#x3C;ul&#x3E;
&#x3C;li&#x3E;I was &#x3C;em&#x3E;technically&#x3C;/em&#x3E; using Apple Music for &#x3C;a href=&#x22;https://support.apple.com/en-us/118285&#x22;&#x3E;Sync Library&#x3C;/a&#x3E; for easy sync between my machines and iDevices, but music streaming services are incomplete/underwhelming at best and &#x3C;a href=&#x22;https://www.theguardian.com/music/2025/sep/18/massive-attack-remove-music-from-spotify-to-protest-ceo-daniel-eks-investment-in-ai-military&#x22;&#x3E;complicit in war at worst&#x3C;/a&#x3E;.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;Album shuffling, or at the very least, a way to quickly pick albums at random.&#x3C;/li&#x3E;
&#x3C;li&#x3E;Scrobbling, I wasn&#x27;t going to give up on 10+ years of listening data, damnit.&#x3C;/li&#x3E;
&#x3C;li&#x3E;At minimum, a macOS app &#x3C;em&#x3E;and&#x3C;/em&#x3E; an iOS app that don&#x27;t look like ass.&#x3C;/li&#x3E;
&#x3C;li&#x3E;And perhaps the most important: being able to handle a huge library without falling apart.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;I had used &#x3C;a href=&#x22;https://www.plex.tv/plexamp/&#x22;&#x3E;Plexamp&#x3C;/a&#x3E; on iOS for a minute a few years prior and, while a Mac app &#x3C;em&#x3E;does&#x3C;/em&#x3E; exist for it... it&#x27;s essentially the iPhone app in a macOS window. I&#x27;m sure this works great if you have a few hundreds albums, but it very much doesn&#x27;t if you have &#x3C;em&#x3E;thousands&#x3C;/em&#x3E;. And it doesn&#x27;t have album shuffling, and Plex is &#x3C;em&#x3E;really&#x3C;/em&#x3E; not good at handling music files if you care about tagging. I assume Jellyfin would suffer from similar problems because it&#x27;s not &#x3C;em&#x3E;designed&#x3C;/em&#x3E; for music.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I had been a &#x3C;a href=&#x22;https://brushedtype.co/doppler/&#x22;&#x3E;Doppler&#x3C;/a&#x3E; user on iOS for a while, and have tried the macOS version and... same deal, no album shuffling and no real solution for syncing either. &#x3C;a href=&#x22;https://radiccio.music/&#x22;&#x3E;Radiccio&#x3C;/a&#x3E; seemed like a promising new music player...until I tried it and it could &#x3C;em&#x3E;not&#x3C;/em&#x3E; handle my library.&#x3C;/p&#x3E;
&#x3C;p&#x3E;After many deliberations, I remembered I already host a bunch of stuff on my NAS/Home server so I figured I&#x27;d give &#x3C;a href=&#x22;https://www.navidrome.org/&#x22;&#x3E;Navidrome&#x3C;/a&#x3E; a try. Setting it up was fairly easy, I already had a copy of my music library (because of the previous Plex stint) so I just had to point it at the files and... it worked great.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Now, I needed clients. The &#x22;macOS native Navidrome/Subsonic clients&#x22; ecosystem is relatively dry at the moment. &#x3C;a href=&#x22;https://github.com/BLeeEZ/amperfy&#x22;&#x3E;Amperfy&#x3C;/a&#x3E; came up a lot but it lacked my precious album shuffling, so it was a pass.&#x3C;/p&#x3E;
&#x3C;p&#x3E;On the Mac, I ended up settling on &#x3C;a href=&#x22;https://github.com/jeffvli/feishin&#x22;&#x3E;Feishin&#x3C;/a&#x3E;. The Spotify-like UI definitely took some getting used to but it runs pretty well, the developer is fairly responsive/updates it regularly, and it&#x27;s an Electron app meaning I can easily &#x3C;a href=&#x22;https://github.com/jeffvli/feishin/commits?author=eramdam&#x22;&#x3E;contribute fixes&#x3C;/a&#x3E; to bugs when I see them.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/feishin-showcase.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/feishin-showcase.webp&#x22; alt=&#x22;&#x26;quot;How Feishin looks like for me&#x26;quot;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;&#x22;How Feishin looks like for me&#x22;&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;On iOS, &#x3C;a href=&#x22;https://testflight.apple.com/join/LDWqgjAs&#x22;&#x3E;Arpeggi&#x3C;/a&#x3E; has been my daily driver. It looks nice, fits pretty well on iOS, and the transcoding feature is &#x3C;em&#x3E;very&#x3C;/em&#x3E; handy when on a cellular network&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-4&#x22; id=&#x22;user-content-fnref-4&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;4&#x3C;/a&#x3E;&#x3C;/sup&#x3E;, I&#x27;ll happily pay for it (even with a subscription) when it officially comes out.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I am still managing files with &#x3C;a href=&#x22;https://beets.readthedocs.io/en/stable/&#x22;&#x3E;beets&#x3C;/a&#x3E; on the NAS directly. I did create a new library from scratch to re-tag things properly. I eventually &#x22;upgraded&#x22; my whole library to FLAC files and took the time to match as many things on &#x3C;a href=&#x22;https://musicbrainz.org/&#x22;&#x3E;MusicBrainz&#x3C;/a&#x3E; as possible; this meant adding releases when they weren&#x27;t already present.
Yes, this took forever, but it makes me happy &#x3C;em&#x3E;and&#x3C;/em&#x3E; I&#x27;ll be able to &#x3C;a href=&#x22;https://beets.readthedocs.io/en/stable/plugins/mbsync.html&#x22;&#x3E;sync changes from MusicBrainz&#x3C;/a&#x3E;, which is neat.&#x3C;/p&#x3E;
&#x3C;p&#x3E;At this point, the workflow is pretty solid, I&#x27;ve been living like this for 4 months. I&#x27;m still sad about the state of software on macOS but I did gain something: control.&#x3C;br /&#x3E;
Neither Navidrome nor Feishin can modify my stuff, only I can, and if something blows up it&#x27;s because &#x3C;strong&#x3E;I&#x3C;/strong&#x3E; fucked up and not because of an obscure bug with Music.app.&#x3C;/p&#x3E;
&#x3C;p&#x3E;And that control feels great nowadays.&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;~26,000 tracks across ~2,500 albums as of writing &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-2&#x22;&#x3E;
&#x3C;p&#x3E;I know some people do it but shuffling individual songs sounds deranged and shuffling songs &#x3C;strong&#x3E;within&#x3C;/strong&#x3E; an album ought to be a crime. &#x3C;a href=&#x22;#user-content-fnref-2&#x22; data-footnote-backref aria-label=&#x22;Back to reference 2&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-3&#x22;&#x3E;
&#x3C;p&#x3E;See &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Big_O_notation&#x22;&#x3E;Big-O notation&#x3C;/a&#x3E;, essentially, the code is written in a way that the more items there are to process...the longer it takes to run. Which &#x3C;em&#x3E;could&#x3C;/em&#x3E; be fine unless your code runs in a way that it taking more than a few miliseconds to run results in the app being unresponsive. &#x3C;a href=&#x22;#user-content-fnref-3&#x22; data-footnote-backref aria-label=&#x22;Back to reference 3&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-4&#x22;&#x3E;
&#x3C;p&#x3E;On the advice of my friend &#x3C;a href=&#x22;https://jkap.io/&#x22;&#x3E;Jae&#x3C;/a&#x3E;, I&#x27;ve set it up to transcode files to OPUS at 96kbps which is &#x3C;em&#x3E;plenty&#x3C;/em&#x3E; when I&#x27;m on the go. &#x3C;a href=&#x22;#user-content-fnref-4&#x22; data-footnote-backref aria-label=&#x22;Back to reference 4&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/macos-tahoe-forced-me-to-abandon-musicapp&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Updates: March 2026</title>
          <link href="https://damien.zone/updates-march-2026" rel="alternate"/>
          <id>https://damien.zone/updates-march-2026</id>
          <published>2026-03-11T03:58:38Z</published>
          <updated>2026-03-12T02:07:52Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;It&#x27;s been a minute, hasn&#x27;t it. In fact it has been &#x3C;em&#x3E;checks notes&#x3C;/em&#x3E; &#x3C;strong&#x3E;10 months&#x3C;/strong&#x3E;?! Oh dear, well. Better late than never I suppose. If you&#x27;re reading this directly on the website (and you should, imo), you&#x27;ll see that things look quite different!&#x3C;/p&#x3E;
&#x3C;p&#x3E;I&#x27;ve been meaning to touch up my website&#x27;s design for, uh, most of last year to be honest but I haven&#x27;t been able to get to it until a few weeks ago. So here it is. It&#x27;s more of a reskin rather than a redesign but it feels fresher, lighter and tidier in ways I like so I&#x27;m pretty happy with it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I&#x27;ve stuck to the excellent &#x3C;a href=&#x22;https://fontsource.org/fonts/atkinson-hyperlegible-next&#x22;&#x3E;Atkinson Hyperlegible Next&#x3C;/a&#x3E;&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E; as a body font and switched the headings from &#x3C;a href=&#x22;https://fonts.google.com/specimen/Merriweather&#x22;&#x3E;Merriweather&#x3C;/a&#x3E; to &#x3C;a href=&#x22;https://pangrampangram.com/products/right-serif&#x22;&#x3E;Pangrampangram&#x27;s Right Serif&#x3C;/a&#x3E;, I think they look quite neat.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I&#x27;ve made the website overall feel a bit more &#x22;professional&#x22;. Not that I intend to write super serious stuff or anything but I eventually want to make I made &#x3C;a href=&#x22;https://erambert.me&#x22;&#x3E;https://erambert.me&#x3C;/a&#x3E; redirect to this website and to avoid maintaining two websites with a &#x3C;em&#x3E;very&#x3C;/em&#x3E; similar purpose&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-2&#x22; id=&#x22;user-content-fnref-2&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;2&#x3C;/a&#x3E;&#x3C;/sup&#x3E;.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;little-details&#x22;&#x3E;Little details&#x3C;/h2&#x3E;
&#x3C;p&#x3E;I&#x27;ve had fun with some details in the design so now I&#x27;m just gonna show them off.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I&#x27;m using the shit out of CSS variables custom properties, meaning that all the colors in the theme are derived from 3 base colors, which means I can do stuff like this&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-3&#x22; id=&#x22;user-content-fnref-3&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;3&#x3C;/a&#x3E;&#x3C;/sup&#x3E;:&#x3C;/p&#x3E;

  
     &#x3C;span&#x3E;Change the color here and see how it affects the style&#x3C;/span&#x3E;
  

&#x3C;p&#x3E;And the color system means that making a dark mode involved &#x3C;a href=&#x22;https://github.com/eramdam/damien.zone/blob/2026-redesign/src/assets/styles/redesign.damien.zone.css#L73-L86&#x22;&#x3E;changing a few colors&#x3C;/a&#x3E; and it looked great right away! &#x3C;small&#x3E;Huge thanks to &#x3C;a href=&#x22;https://blog.platinumtulip.net/&#x22;&#x3E;Tulip&#x3C;/a&#x3E; for helping me with these&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Hover states for links are always a struggle for me, so I decided to stop worrying about it and going whole hog with it and making them &#x3C;strong&#x3E;very&#x3C;/strong&#x3E; obvious:&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/2026-redesign-hoverstate.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/2026-redesign-hoverstate.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;I wanted to have &#x3C;em&#x3E;some&#x3C;/em&#x3E; fancy/flashy touches in the redesign, so I opted for this progressive blur effect in the sticky header on compatible browsers, I think it looks cute. Kudos to &#x3C;a href=&#x22;https://kennethnym.com/blog/progressive-blur-in-css/&#x22;&#x3E;kennethnym&#x3C;/a&#x3E; because I wouldn&#x27;t have bothered to figure it out myself, I think.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/2026-redesign-blur-header.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/2026-redesign-blur-header.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;While on the topic of blurs, you know what&#x27;s better than a colored shadow? A shadow that matches the image&#x27;s colors. It&#x27;s barely noticeable but I know it&#x27;s there and it makes me happy&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/2026-redesign-avatarshadoa.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/2026-redesign-avatarshadoa.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;One thing I noticed when working on this redesign was how I really did not like the default Comentario avatar for anonymous comments. It does the job but it felt really jarring in my opinion:&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/comentario-default-avatar.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/comentario-default-avatar.png&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;So I tried to come up with something, and I didn&#x27;t want to &#x3C;em&#x3E;just&#x3C;/em&#x3E; replace the default avatar with something else so I thought &#x22;could I somehow make something more unique and (more importantly) cuter?&#x22;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;So I did! I will make a whole article about it because I don&#x27;t want to derail this post too much but here&#x27;s how it looks. It &#x3C;em&#x3E;looks&#x3C;/em&#x3E; random but isn&#x27;t really (more on that in the future post) and retains the same &#x22;random&#x22; avatar if an anonymous commenter reuses the same name.&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-4&#x22; id=&#x22;user-content-fnref-4&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;4&#x3C;/a&#x3E;&#x3C;/sup&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/2026-redesign-anonavatars.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/2026-redesign-anonavatars.png&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;That&#x27;s it &#x2728; I want to post more on this website this year, I swear I will (at least try to) stick to that this time around.&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;#eggbug forever &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-2&#x22;&#x3E;
&#x3C;p&#x3E;I am, however, not gonna even &#x3C;em&#x3E;think&#x3C;/em&#x3E; about migrating shit like email away from that domain. &#x3C;a href=&#x22;#user-content-fnref-2&#x22; data-footnote-backref aria-label=&#x22;Back to reference 2&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-3&#x22;&#x3E;
&#x3C;p&#x3E;I would have made a video but A) this is funnier and B) this weighs nothing&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-5&#x22; id=&#x22;user-content-fnref-5&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;5&#x3C;/a&#x3E;&#x3C;/sup&#x3E; &#x3C;a href=&#x22;#user-content-fnref-3&#x22; data-footnote-backref aria-label=&#x22;Back to reference 3&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-4&#x22;&#x3E;
&#x3C;p&#x3E;In case you&#x27;re wondering, these are emoji taken from &#x3C;a href=&#x22;https://emojipedia.org/noto-emoji&#x22;&#x3E;Noto Emoji (monochrome)&#x3C;/a&#x3E; &#x3C;a href=&#x22;#user-content-fnref-4&#x22; data-footnote-backref aria-label=&#x22;Back to reference 4&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-5&#x22;&#x3E;
&#x3C;p&#x3E;Unfortunately styling the color input in CSS is not possible consistently yet and I am not bothering to write a custom color input &#x3C;a href=&#x22;#user-content-fnref-5&#x22; data-footnote-backref aria-label=&#x22;Back to reference 5&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/updates-march-2026&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Justice in San Francisco, May 22nd, 2025</title>
          <link href="https://damien.zone/justice-in-san-francisco-may-22nd-2025" rel="alternate"/>
          <id>https://damien.zone/justice-in-san-francisco-may-22nd-2025</id>
          <published>2025-05-25T08:36:47Z</published>
          <updated>2025-05-25T17:39:15Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;In a very on-brand move, I saw Justice live in San Francisco last Thursday&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;, I took a bunch of pictures. BUT! This time, I used my newly-acquired Ricoh GR III, because what better way to really get familiarized with a camera than to use it to take hundreds of pictures for 3 hours in a dark environment, right?&#x3C;/p&#x3E;
&#x3C;p&#x3E;Anyway, I got some pretty good ones, the Ricoh&#x27;s resolution gives so much flexibility when cropping that the short focal length (28mm in 35mm equivalent) wasn&#x27;t as big of an issue as I feared. And I wasn&#x27;t even standing remotely close from the stage!&#x3C;/p&#x3E;
&#x3C;p&#x3E;As always, click the images to see the full-size, full quality JPEGs. Only the third picture was taken with the iPhone 13 Pro using Halide, everything else was with the Ricoh.&#x3C;/p&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/justice-05-2025/justice-05-2025-8.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/justice-05-2025/justice-05-2025-8-thumb.webp&#x22; alt=&#x22;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/justice-05-2025/justice-05-2025-1.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/justice-05-2025/justice-05-2025-1-thumb.webp&#x22; alt=&#x22;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/justice-05-2025/justice-05-2025-2.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/justice-05-2025/justice-05-2025-2-thumb.webp&#x22; alt=&#x22;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/justice-05-2025/justice-05-2025-3.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/justice-05-2025/justice-05-2025-3-thumb.webp&#x22; alt=&#x22;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/justice-05-2025/justice-05-2025-4.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/justice-05-2025/justice-05-2025-4-thumb.webp&#x22; alt=&#x22;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/justice-05-2025/justice-05-2025-5.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/justice-05-2025/justice-05-2025-5-thumb.webp&#x22; alt=&#x22;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/justice-05-2025/justice-05-2025-6.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/justice-05-2025/justice-05-2025-6-thumb.webp&#x22; alt=&#x22;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/justice-05-2025/justice-05-2025-7.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/justice-05-2025/justice-05-2025-7-thumb.webp&#x22; alt=&#x22;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/justice-05-2025/justice-05-2025-9.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/justice-05-2025/justice-05-2025-9-thumb.webp&#x22; alt=&#x22;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/justice-05-2025/justice-05-2025-10.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/justice-05-2025/justice-05-2025-10-thumb.webp&#x22; alt=&#x22;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;For those counting, that&#x27;s 5 times during their current world tour. &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/justice-in-san-francisco-may-22nd-2025&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Mac Themes Garden: post-launch updates</title>
          <link href="https://damien.zone/mac-themes-garden-post-launch-updates" rel="alternate"/>
          <id>https://damien.zone/mac-themes-garden-post-launch-updates</id>
          <published>2025-05-21T06:07:16Z</published>
          <updated>2025-05-21T06:08:43Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/macthemes-update.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/macthemes-update.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;post-launch-stuff&#x22;&#x3E;Post-launch stuff&#x3C;/h2&#x3E;
&#x3C;p&#x3E;It has been a fun two weeks since I launched &#x3C;a href=&#x22;https://macthemes.garden&#x22;&#x3E;Mac Themes Garden&#x3C;/a&#x3E;!&#x3C;br /&#x3E;
I had published my little &#x3C;a href=&#x22;/introducing-mac-themes-garden&#x22;&#x3E;blog post&#x3C;/a&#x3E;, posted about it on &#x3C;a href=&#x22;https://social.erambert.me/@eramdam/114458779438545155&#x22;&#x3E;Mastodon&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://bsky.app/profile/damien.zone/post/3lohwzfkglc2o&#x22;&#x3E;Bluesky&#x3C;/a&#x3E; at like 9pm without thinking much of it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Only to wake up to being on &#x3C;a href=&#x22;https://news.ycombinator.com/item?id=43919868&#x22;&#x3E;Hacker News&#x3C;/a&#x3E;?! The (in)famous Orange Site! And somehow the thread was full of people just reminiscing and sharing some of their favorite themes they looked for on the site?! Bonkers stuff. But I&#x27;m not complaining.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Made for a funny set of stats, let me tell you:&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/macthemes-garden-stats.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/macthemes-garden-stats.png&#x22; alt=&#x22;My analytics showing a 1460% increase of visitor in 24h for macthemes.garden&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;My analytics showing a 1460% increase of visitor in 24h for macthemes.garden&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/damien-zone-stats.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/damien-zone-stats.png&#x22; alt=&#x22;My analytics showing a 10,543% increase of visitor in 24h for damien.zone&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;My analytics showing a 10,543% increase of visitor in 24h for damien.zone&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Then &#x3C;a href=&#x22;https://boingboing.net/2025/05/08/site-has-all-the-classic-macos-themes-you-could-ever-want.html&#x22;&#x3E;Boing Boing&#x3C;/a&#x3E; posted about it, so did &#x3C;a href=&#x22;https://mjtsai.com/blog/2025/05/09/mac-themes-garden/&#x22;&#x3E;Michael Tsai&#x3C;/a&#x3E;, and then today (as I write this) &#x3C;a href=&#x22;https://9to5mac.com/2025/05/18/mac-themes-garden-kaleidoscope-archive/&#x22;&#x3E;9to5Mac&#x3C;/a&#x3E; also posted about it. I almost expect a second, much smaller wave, of visits if other websites pick it up from 9to5Mac.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Wild stuff, but it has been great to see the response to the website, pretty rewarding and motivating!&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;some-updates&#x22;&#x3E;Some updates!&#x3C;/h2&#x3E;
&#x3C;p&#x3E;Right as I launched the site, &#x3C;a href=&#x22;https://hypercritical.co/&#x22;&#x3E;John Siracusa&#x3C;/a&#x3E; made a very good suggestion:&#x3C;/p&#x3E;
&#x3C;blockquote class=&#x22;mastodon-embed&#x22; data-embed-url=&#x22;https://mastodon.social/@siracusa/114458934614680148/embed&#x22; style=&#x22;background:#FCF8FF;border-radius:8px;border:1px solid #C9C4DA;margin:0;max-width:540px;min-width:270px;overflow:hidden;padding:0&#x22;&#x3E; &#x3C;a href=&#x22;https://mastodon.social/@siracusa/114458934614680148&#x22; target=&#x22;_blank&#x22; style=&#x22;align-items:center;color:#1C1A25;display:flex;flex-direction:column;font-family:system-ui, -apple-system, BlinkMacSystemFont, &#x27;Segoe UI&#x27;, Oxygen, Ubuntu, Cantarell, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, Roboto, sans-serif;font-size:14px;justify-content:center;letter-spacing:0.25px;line-height:20px;padding:24px;text-decoration:none&#x22;&#x3E;  &#x3C;div style=&#x22;color:#787588;margin-top:16px&#x22;&#x3E;Post by @siracusa@mastodon.social&#x3C;/div&#x3E; &#x3C;div style=&#x22;font-weight:500&#x22;&#x3E;View on Mastodon&#x3C;/div&#x3E; &#x3C;/a&#x3E; &#x3C;/blockquote&#x3E; 
&#x3C;p&#x3E;So implementing these suggestions (sorting and &#x22;likes&#x22;) has been what I&#x27;ve been doing for the past week and a half.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;sorting&#x22;&#x3E;Sorting&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://github.com/eramdam/macthemes.garden/pull/5&#x22;&#x3E;Sorting&#x3C;/a&#x3E; was relatively straightforward, I just had to get a bit creative because I didn&#x27;t want to use Astro&#x27;s server rendering &#x3C;em&#x3E;just&#x3C;/em&#x3E; to sort items. So I used the &#x3C;a href=&#x22;https://docs.astro.build/en/guides/routing/#nested-pagination&#x22;&#x3E;nested pagination&#x3C;/a&#x3E; mechanism to generate the ~320 pages necessary, not too bad:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame has-title&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;span class=&#x22;title&#x22;&#x3E;src/pages/[sort]/[page].astro&#x3C;/span&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;astro&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#99A0A6;--1:#616972&#x22;&#x3E;---&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;type&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { GetStaticPaths } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;astro&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { getCollection } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;astro:content&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; IndexPage &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;../../components/IndexPage.astro&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { PAGINATION, slugFromSortAndOrder, sortThemes } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;../../helpers&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { possibleSortSlugs } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;../../helpers&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;export&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;getStaticPaths&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;async&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; ({ &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;paginate&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; }) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;themes&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;getCollection&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;themes&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; possibleSortSlugs.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;flatMap&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;slug&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;order&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;sort&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;slugFromSortAndOrder&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(slug);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;paginate&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;sortThemes&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(themes, sort, order), {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;pageSize: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;PAGINATION&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.size,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;params: { sort: slug },&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;satisfies&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;GetStaticPaths&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;page&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; Astro.props;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;order&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;sort&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;slugFromSortAndOrder&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(Astro.params.sort);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#99A0A6;--1:#616972&#x22;&#x3E;---&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;IndexPage&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;page&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;={page} &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;order&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;={order} &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;sort&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;={sort} /&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;h3 id=&#x22;user-likes&#x22;&#x3E;User likes&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://github.com/eramdam/macthemes.garden/pull/6&#x22;&#x3E;Likes&#x3C;/a&#x3E;... were a Whole Thing as I expected. I knew I wanted to do two things:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;Accept &#x22;user&#x22; likes. Users are &#x22;identified&#x22; using a &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based)&#x22;&#x3E;UUID v5&#x3C;/a&#x3E; generated with their IP address as a namespace, making for a convenient hash. It&#x27;s not perfect, but I&#x27;m not going to bother setting up an actual user login system just for a little &#x22;like&#x22; button.&#x3C;/li&#x3E;
&#x3C;li&#x3E;Use the likes on posts from the &#x3C;a href=&#x22;https://social.erambert.me/@macthemes&#x22;&#x3E;Mastodon&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://bsky.app/profile/macthemes.garden&#x22;&#x3E;Bluesky&#x3C;/a&#x3E; profiles.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;This was a perfect excuse to get familiar with &#x3C;a href=&#x22;https://docs.astro.build/en/guides/astro-db/&#x22;&#x3E;Astro DB&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;My &#x3C;a href=&#x22;https://github.com/eramdam/macthemes.garden/blob/6e646c2b5ba8d70172783ce405f0ff24eb736257/db/config.ts#L1&#x22;&#x3E;database schema&#x3C;/a&#x3E; is relatively simple:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;A &#x3C;code&#x3E;Like&#x3C;/code&#x3E; table with the following columns:
&#x3C;ul&#x3E;
&#x3C;li&#x3E;&#x3C;code&#x3E;id&#x3C;/code&#x3E; (unique/primary key) which is a UUID v4&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;code&#x3E;themeId&#x3C;/code&#x3E;, which references a specific theme in the &#x3C;code&#x3E;Theme&#x3C;/code&#x3E; table&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;code&#x3E;userId&#x3C;/code&#x3E;&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;A &#x3C;code&#x3E;Theme&#x3C;/code&#x3E; table with:
&#x3C;ul&#x3E;
&#x3C;li&#x3E;a &#x3C;code&#x3E;id&#x3C;/code&#x3E; column which corresponds to the &#x3C;a href=&#x22;https://github.com/eramdam/macthemes.garden/blob/6e646c2b5ba8d70172783ce405f0ff24eb736257/src/themesLoader.ts#L28-L31&#x22;&#x3E;actual IDs I give each theme&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;A &#x3C;code&#x3E;UserRequest&#x3C;/code&#x3E; table with a &#x3C;code&#x3E;userId&#x3C;/code&#x3E; and a &#x3C;code&#x3E;date&#x3C;/code&#x3E; column, this is used to do basic rate-limiting on the &#x22;like&#x22; &#x3C;a href=&#x22;https://docs.astro.build/en/guides/actions/&#x22;&#x3E;action&#x3C;/a&#x3E;.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;The aforementioned action&#x27;s &#x3C;a href=&#x22;https://github.com/eramdam/macthemes.garden/blob/6e646c2b5ba8d70172783ce405f0ff24eb736257/src/actions/index.ts&#x22;&#x3E;code&#x3C;/a&#x3E; is a bit verbose, but the logic is relatively simple:&#x3C;/p&#x3E;
&#x3C;ol&#x3E;
&#x3C;li&#x3E;Receive a user request&#x3C;/li&#x3E;
&#x3C;li&#x3E;Do basic validation to ensure the &#x3C;code&#x3E;themeId&#x3C;/code&#x3E; being set matches one of the themes&#x3C;/li&#x3E;
&#x3C;li&#x3E;Check against the rate-limiter to see if the user is allowed to perform the action&#x3C;/li&#x3E;
&#x3C;li&#x3E;Look if the theme being liked already has a corresponding row in &#x3C;code&#x3E;Theme&#x3C;/code&#x3E; and if not, insert it.&#x3C;/li&#x3E;
&#x3C;li&#x3E;Insert/delete a row from the &#x3C;code&#x3E;Like&#x3C;/code&#x3E; table depending on whether the user is liking/unliking the theme.&#x3C;/li&#x3E;
&#x3C;li&#x3E;Return the total likes count for the theme and the &#x3C;code&#x3E;liked&#x3C;/code&#x3E; state for the current user.&#x3C;/li&#x3E;
&#x3C;li&#x3E;Have the UI update as the action is performed with a simple &#x3C;a href=&#x22;https://github.com/eramdam/macthemes.garden/blob/6e646c2b5ba8d70172783ce405f0ff24eb736257/src/components/likeButton.tsx#L12-L32&#x22;&#x3E;Preact component&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;h3 id=&#x22;mastodonbluesky-likes&#x22;&#x3E;Mastodon/Bluesky likes&#x3C;/h3&#x3E;
&#x3C;p&#x3E;That&#x27;s for user-generated likes, next is pulling the likes from Mastodon and Bluesky.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I went with solutions that one might call &#x22;lazy&#x22; or &#x22;stupid&#x22;, to which I would answer &#x22;if it is stupid, and it works, then it&#x27;s not stupid&#x22;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Since I host my own Mastodon instance, I can bypass the API entirely to get the basis of what I need data-wise. So I wrote a little script that calls PostgreSQL and generates a JSON file that looks like this:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;json&#x22; class=&#x22;wrap&#x22; style=&#x22;--ecMaxLine:116ch&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;[&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:2ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:4ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;&#x22;text&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;Orange&#x27;N&#x27;Blue - John Bloor&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;\n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;https://macthemes.garden/themes/6471b22c97c7-OrangeNBlue&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:4ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;&#x22;reblogs_count&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;2&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:4ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;&#x22;favourites_count&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;6&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:2ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;},&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:4ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:4ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;&#x22;text&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;fvwMac green 1.09 - Alexander E. Ribbe&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;\n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;https://macthemes.garden/themes/739da6aef9f0-fvwMac-green-109&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:4ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;&#x22;reblogs_count&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:4ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;&#x22;favourites_count&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;2&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:2ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;},&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22; style=&#x22;--ecIndent:2ch&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#99A0A6;--1:#616972&#x22;&#x3E;// and so on...&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;]&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;The script is basically one cursed SQL query, behold:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame is-terminal&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;span class=&#x22;title&#x22;&#x3E;&#x3C;/span&#x3E;&#x3C;span class=&#x22;sr-only&#x22;&#x3E;Terminal window&#x3C;/span&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;bash&#x22; class=&#x22;wrap&#x22; style=&#x22;--ecMaxLine:457ch&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;psql&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;--dbname=mastodon_production&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-c&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;SELECT json_agg(json_build_object(&#x27;text&#x27;, s.text, &#x27;reblogs_count&#x27;, ss.reblogs_count, &#x27;favourites_count&#x27;, ss.favourites_count)) FROM statuses s JOIN status_stats ss ON s.id=ss.status_id WHERE s.account_id=113370184750103599 AND s.in_reply_to_id IS NULL AND s.text LIKE &#x27;%https://macthemes.garden/themes/%&#x27; AND (ss.reblogs_count&#x26;gt;0 OR ss.favourites_count&#x26;gt;0);&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-t&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-A&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-o&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;/home/mastodon/live/public/macthemes-posts-stats.json&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;The file is then made available publicly on my &#x3C;a href=&#x22;https://social.erambert.me/macthemes-posts-stats.json&#x22;&#x3E;instance&#x27;s server&#x3C;/a&#x3E; and is consumed by &#x3C;a href=&#x22;https://github.com/eramdam/macthemes.garden/blob/main/scripts/grab-mastodon-likes.ts&#x22;&#x3E;a script&#x3C;/a&#x3E; that runs periodically in a GitHub action that will grab the URLs, extract the IDs, add the reblogs and favorites and make one big JSON map that will be used at build-time to add onto the like count.&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame has-title&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;span class=&#x22;title&#x22;&#x3E;grab-mastodon-likes.ts&#x3C;/span&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;ts&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; fs &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;fs-extra&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#99A0A6;--1:#616972&#x22;&#x3E;// File generated daily&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;stats&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;fetch&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://social.erambert.me/macthemes-posts-stats.json&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;statsObject&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;text&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;string&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;reblogs_count&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;number&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;favourites_count&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;number&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}[] &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; stats.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;json&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;();&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;urlRegex&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;RegExp&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://macthemes.garden/themes/([a-z0-9]+)&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;i&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;likesByThemeIds&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; statsObject&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;map&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;obj&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; [, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;themeId&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;] &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; obj.text.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;match&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(urlRegex) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;||&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; [];&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;!&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;themeId) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;undefined&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;...&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;obj, themeId };&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;})&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;filter&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(Boolean)&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;reduce&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;prev&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;curr&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;!&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;curr?.themeId) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {};&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;...&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;prev,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;[curr?.themeId]:&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(prev[curr.themeId] &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;||&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;+&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(curr.favourites_count &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;||&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;+&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(curr.reblogs_count &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;||&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;};&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}, {});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; fs.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;writeFile&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;URL&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;meta&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;resolve&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;../src/themes/likes-mastodon.json&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)).pathname,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;JSON&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;stringify&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;likes: likesByThemeIds,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;},&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;null&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;2&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;utf-8&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;For Bluesky, I&#x27;m doing something that feels like it shouldn&#x27;t work, but it does and is much less annoying to write than the &#x22;correct&#x22; way so I&#x27;ll take it. I&#x27;m abusing the &#x3C;a href=&#x22;https://docs.bsky.app/blog/repo-export&#x22;&#x3E;AT Proto repo export&#x3C;/a&#x3E; mechanism to get an entire archive of the bot&#x27;s account, I parse it as a collection of records and fetch the corresponding posts from the Bluesky API to get the necessary metrics. It&#x27;s a bit silly, but it feels more efficient than having to query multiple pages of posts to &#x3C;em&#x3E;maybe&#x3C;/em&#x3E; find the right ones.&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;ts&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { iterateAtpRepo } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;@atcute/car&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { Client, CredentialManager } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;@atcute/client&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; fs &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;fs-extra&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { chunk } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;lodash-es&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#99A0A6;--1:#616972&#x22;&#x3E;// import lexicons&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;type&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {} &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;@atcute/atproto&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;type&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {} &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;@atcute/bluesky&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;actor&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;did:plc:a5j6hkim467cvi4rzouh6aei&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;manager&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;CredentialManager&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;({ service: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://bsky.social&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; });&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;rpc&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;Client&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;({ handler: manager });&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; manager.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;login&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;({&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;identifier: process.env.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;BLUESKY_USERNAME&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;||&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;password: process.env.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;BLUESKY_PASSWORD&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;||&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;data&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;ok&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; rpc.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;get&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;com.atproto.sync.getRepo&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;as: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;bytes&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;params: {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;did: actor,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;},&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;!&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;ok) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;process.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;exit&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;urlRegex&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;RegExp&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://macthemes.garden/themes/([a-z0-9]+)&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;i&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;records&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;rkey&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;string&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;themeId&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;string&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; }[] &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; [];&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#99A0A6;--1:#616972&#x22;&#x3E;// convenient iterator for reading through an AT Protocol CAR repository&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;for&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;collection&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;rkey&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;record&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;of&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;iterateAtpRepo&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(data)) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (collection &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;===&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;app.bsky.feed.post&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(record &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;as&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;any&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;).facets?.[&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;].features?.[&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;].$type &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;===&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;app.bsky.richtext.facet#link&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(record &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;as&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;any&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;).facets?.[&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;].features?.[&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;].uri.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;startsWith&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://macthemes.garden/themes/&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; [, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;themeId&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;] &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;String&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((record &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;as&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;any&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;).facets?.[&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;].features?.[&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;].uri).&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;match&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;            &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;urlRegex,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;||&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; [];&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (themeId) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;records.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;push&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;({ themeId, rkey });&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;let&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; likesByThemeIds&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;Record&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;string&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;number&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {};&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;for&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;recordsChunk&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;of&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;chunk&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(records, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;25&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;data&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;ok&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; rpc.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;get&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;app.bsky.feed.getPosts&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;params: {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;uris: recordsChunk.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;map&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;r&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;makeUri&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(r.rkey)),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;},&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (ok) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;data.posts.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;forEach&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;post&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;themeIdForPost&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; recordsChunk.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;find&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;r&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;makeUri&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(r.rkey) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;===&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; post.uri;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;})?.themeId;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (themeIdForPost) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;likesByThemeIds[themeIdForPost] &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(likesByThemeIds[themeIdForPost] &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;||&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;+&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(post.likeCount &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;||&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;+&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(post.repostCount &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;||&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; fs.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;writeFile&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;URL&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;meta&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;resolve&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;../src/themes/likes-bsky.json&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)).pathname,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;JSON&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;stringify&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;likes: likesByThemeIds,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;},&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;null&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;2&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;utf-8&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;function&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;makeUri&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;rkey&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;string&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;any&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x60;at://${&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;actor&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;}/app.bsky.feed.post/${&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;rkey&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;}&#x60;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;And just like the Mastodon script, it is running periodically in a GitHub action, so the data is refreshed at least once a day.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;putting-all-this-together&#x22;&#x3E;Putting all this together&#x3C;/h3&#x3E;
&#x3C;p&#x3E;A few tweaks of the theme grid layout and some cute icons drawn by my friend &#x3C;a href=&#x22;https://wavebeem.com&#x22;&#x3E;Sage&#x3C;/a&#x3E; later, I got myself a cute &#x22;likes&#x22; view on the theme grid!&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/macthemes-garden-grid.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/macthemes-garden-grid.png&#x22; alt=&#x22;Robo-K2 really is one of the themes of all time&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Robo-K2 really is one of the themes of all time&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;And that&#x27;s it for the updates! I got other ideas, but they will be a bit more involved so they might take some time to execute, so stay tuned! And keep sharing the good themes around &#x2764;&#xFE0F;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Cheers,&#x3C;br /&#x3E;
- Damien&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/mac-themes-garden-post-launch-updates&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Introducing Mac Themes Garden!</title>
          <link href="https://damien.zone/introducing-mac-themes-garden" rel="alternate"/>
          <id>https://damien.zone/introducing-mac-themes-garden</id>
          <published>2025-05-06T03:12:50Z</published>
          <updated>2026-03-15T14:44:17Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/projects/macthemes-garden.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/projects/macthemes-garden.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;the-short-version&#x22;&#x3E;The short version&#x3C;/h2&#x3E;
&#x3C;p&#x3E;I&#x27;ve &#x22;launched&#x22; the &#x3C;a href=&#x22;https://macthemes.garden&#x22;&#x3E;Mac Themes Garden&#x3C;/a&#x3E;! It is a website showcasing more than 3,000 (and counting) Kaleidoscope from the Classic Mac era, ready to be seen, downloaded and explored! Check it out! Oh, and there also is an &#x3C;a href=&#x22;https://macthemes.garden/feed.xml&#x22;&#x3E;RSS feed&#x3C;/a&#x3E; you can subscribe to see themes as they are added/updated!&#x3C;/p&#x3E;
&#x3C;p&#x3E;And yes, there is a button that you can include on your website! &#x3C;a href=&#x22;https://macthemes.garden/about#buttons&#x22;&#x3E;Grab it here&#x3C;/a&#x3E;! Isn&#x27;t it cute?&#x3C;/p&#x3E;

&#x3C;a href=&#x22;https://macthemes.garden&#x22; title=&#x22;Mac Themes Garden&#x22;&#x3E;&#x3C;img src=&#x22;https://macthemes.garden/buttons/88x31_macthemes.garden.png&#x22; alt=&#x22;Mac Themes Garden&#x22; style=&#x22;image-rendering:pixelated&#x22; /&#x3E;&#x3C;/a&#x3E;

&#x3C;p&#x3E;&#x3C;strong&#x3E;Now, for the yapping.&#x3C;/strong&#x3E; Note: if you&#x27;re reading this in an RSS reader, you might want to open the article on my website directly as it contains a bunch of CSS demos and those won&#x27;t work well in an RSS reader.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;some-background&#x22;&#x3E;Some background&#x3C;/h2&#x3E;
&#x3C;p&#x3E;If you know me from Online, you may know that I&#x27;ve been running the Mac Themes Bot on &#x3C;a href=&#x22;https://bsky.app/profile/macthemes.garden&#x22;&#x3E;Bluesky&#x3C;/a&#x3E;/&#x3C;a href=&#x22;https://social.erambert.me/@macthemes&#x22;&#x3E;Mastodon&#x3C;/a&#x3E;/&#x3C;a href=&#x22;https://cohost.org/macthemes&#x22;&#x3E;Cohost&#x3C;/a&#x3E; for a few years now.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The idea of the bot was simple, showcasing custom themes from the Mac OS X and Classic Mac eras, on the rate of one an hour. Since I was inspired by &#x3C;a href=&#x22;https://web.archive.org/web/20191021204432/https://twitter.com/kaleidoscopemac&#x22;&#x3E;@kaleidoscopemac&#x3C;/a&#x3E; on Twitter, I only started showcasing themes made for &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Unsanity&#x22;&#x3E;ShapeShifter by Unsanity&#x3C;/a&#x3E;. A while later, that Twitter account got suspended.&#x3C;br /&#x3E;
Since I already had the &#x3C;a href=&#x22;https://github.com/eramdam/shapeshifter-themes&#x22;&#x3E;tooling in place&#x3C;/a&#x3E; to scrape and post themes for OS X, I figured I could add themes for Kaleidoscope (OS 7/8/9) into the mix. After trying (and failing) to get the original dataset from the author of the bot, I set on to scrape the Wayback Machine for records of the &#x3C;a href=&#x22;https://web.archive.org/web/20000823055322fw_/http://www.kaleidoscope.net/schemes/completelisting.shtml&#x22;&#x3E;Kaleidoscope Scheme Archive&#x3C;/a&#x3E;.&#x3C;br /&#x3E;
From that point on, my bot would post themes every hour, with a classic theme on even hours and an OS X theme on odd hours&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The years passed, the bot carried on, made me and a bunch of other people smile on the various websites where I would run it. The &#x3C;a href=&#x22;https://cohost.org/macthemes&#x22;&#x3E;Cohost&#x3C;/a&#x3E; incarnation in particular was really special because Cohost was a special site, but also it was full of nerds (complimentary) and people would go nuts for the random gems in there.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Around maybe early 2023, I grew frustrated of the fact that the only images I had for the Kaleidoscope themes schemes were those &#x3C;a href=&#x22;https://github.com/eramdam/shapeshifter-themes/blob/master/assets/!.emperor.gif&#x22;&#x3E;tiny .gif files&#x3C;/a&#x3E; from the late 90s.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;recording-25-year-old-schemes&#x22;&#x3E;&#x201C;Recording&#x201D; 25-year-old schemes&#x3C;/h3&#x3E;
&#x3C;p&#x3E;So I did the reasonable thing: set up a terribly manual process to take screenshots and record the author information of the &#x3C;a href=&#x22;https://archive.org/details/kaleidoscope-scheme-archive&#x22;&#x3E;~4,000 themes available&#x3C;/a&#x3E;, with the intention of making a website showcasing everything once I was done.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Without going into details (which you can read &#x3C;a href=&#x22;https://web.archive.org/web/20250106111834/https://cohost.org/eramdam/post/5246796-replying-to-this-com&#x22;&#x3E;here&#x3C;/a&#x3E;), the process looks like this:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;Open my Mac OS 9 VM in &#x3C;a href=&#x22;https://getutm.app/&#x22;&#x3E;UTM.app&#x3C;/a&#x3E; (QEMU frontend)&#x3C;/li&#x3E;
&#x3C;li&#x3E;Go through the folder of schemes&#x3C;/li&#x3E;
&#x3C;li&#x3E;Select a given scheme, apply it&#x3C;/li&#x3E;
&#x3C;li&#x3E;Take 3 screenshots:
&#x3C;ol&#x3E;
&#x3C;li&#x3E;One of the scheme&#x27;s about box.&#x3C;/li&#x3E;
&#x3C;li&#x3E;One of the scheme being used in the Finder/regular desktop situation.&#x3C;/li&#x3E;
&#x3C;li&#x3E;And finally, a screenshot of the application &#x3C;a href=&#x22;http://www.shurey.com/Soft/Share/KSA/index.html&#x22;&#x3E;KSA Sampler&#x3C;/a&#x3E; in order to mimic the original screenshots from the Kaleidoscope Scheme Archive. That specific screenshot would get pasted into Photoshop to be cropped/trimmed of its opaque background using Photoshop Actions.&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;Write down the name, author and release year of the scheme&#x3C;/li&#x3E;
&#x3C;li&#x3E;Find the corresponding .sit archive file&#x3C;/li&#x3E;
&#x3C;li&#x3E;Record all of this in a record inside an Airtable database.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;Here&#x27;s how it looks inside Airtable:&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/airtable-macthemes.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/airtable-macthemes.png&#x22; alt=&#x22;6 rows inside an Airtable database, showing screenshots and scheme information&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;6 rows inside an Airtable database, showing screenshots and scheme information&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;On a good day, I can maybe record, I don&#x27;t know, a dozen or so themes an hour.&#x3C;/p&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;But Damien, why didn&#x27;t you automate this process?!&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;I&#x27;m glad you asked! I tried! But I, at least until now, could not find a good way to reliably perform the actions I need to take. And that&#x27;s not even touching on the fact that sometimes a scheme doesn&#x27;t have any author or year information! Sometimes the author inside the Kaleidoscope scheme file is completely wrong, and the actual author is written in a separate &#x22;Read me&#x22; file. Sometimes there&#x27;s barely any information to go by, sometimes the scheme is buggy and would crash my VM.&#x3C;/p&#x3E;
&#x3C;p&#x3E;At that point, the only automations I have are:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;a &#x3C;a href=&#x22;https://www.keyboardmaestro.com/main/&#x22;&#x3E;Keyboard Maestro&#x3C;/a&#x3E; &#x3C;a href=&#x22;/img/blog/keyboard-mastro-macro.png&#x22;&#x3E;macro&#x3C;/a&#x3E; that calls the &#x3C;code&#x3E;qemu-monitor&#x3C;/code&#x3E; for the running VM, takes a lossless screenshot and puts it into my clipboard, ready to be pasted&#x3C;/li&#x3E;
&#x3C;li&#x3E;Photoshop actions to:
&#x3C;ul&#x3E;
&#x3C;li&#x3E;create a document from the clipboard&#x3C;/li&#x3E;
&#x3C;li&#x3E;after cropping, remove all pixels of a given color in a document and trim it to remove extra alpha pixels (for the KSA Sampler screenshots above)&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;A &#x3C;a href=&#x22;https://macintoshgarden.org/forum/startly-quickeys-5&#x22;&#x3E;Quickeys&#x3C;/a&#x3E; shortcut to call &#x22;Hide Others&#x22; inside of Mac OS 9. Turns out this action didn&#x27;t have a keyboard shortcut until Mac OS X? Didn&#x27;t know that!&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;Beyond that, I&#x27;m afraid it&#x27;s all manual since I want to record data that isn&#x27;t straight forwardly extracted by just looking at files &#x1F614;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;em&#x3E;At any rate&#x3C;/em&#x3E;, I was and thought &#x22;I&#x27;ll finish recording all these schemes, &#x3C;strong&#x3E;and then&#x3C;/strong&#x3E; I&#x27;ll make the website&#x22;...&#x3C;/p&#x3E;
&#x3C;p&#x3E;Dear reader, I am not done. By my own estimations, I am maybe halfway done. I do not know when I will be fully done, but my good friend &#x3C;a href=&#x22;https://wavebeem.com&#x22;&#x3E;Sage&#x3C;/a&#x3E; pushed me to: make the damn website already.&#x3C;/p&#x3E;
&#x3C;p&#x3E;And they were right, I should have made the website earlier! It was a fun and challenging distraction, and &#x3C;em&#x3E;fuck me&#x3C;/em&#x3E; I could use distractions these days.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;making-da-website&#x22;&#x3E;Making Da Website&#x3C;/h2&#x3E;
&#x3C;p&#x3E;So, around January of this year, I&#x27;ve started work on the website.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The first step was to interface with the &#x3C;a href=&#x22;https://airtable.com/&#x22;&#x3E;Airtable&#x3C;/a&#x3E; API in order to download the data from my database and store all the assets into a folder in my repository.
&#x3C;a href=&#x22;https://github.com/eramdam/macthemes.garden/blob/main/scripts/airtable.ts&#x22;&#x3E;Nothing too crazy&#x3C;/a&#x3E;, but had to be done.&#x3C;br /&#x3E;
I did need to be careful around caching and not re-downloading images I already had on disk. We&#x27;re talking about like, ~2,500 rows each containing 3 images, and you don&#x27;t want to re-download 7,500 PNG files every time the script needs to run.&#x3C;/p&#x3E;
&#x3C;p&#x3E;With the data on hand, the real fun began.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/macthemes-garden-v0.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/macthemes-garden-v0.png&#x22; alt=&#x22;Early version of the Mac Themes Garden site&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Early version of the Mac Themes Garden site&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;The proof-of-concept was using Eleventy which I chose purely because I had just finished remaking my website (you&#x27;re reading it now!) using it, so I figured it would be a good fit because of its simplicity and speed.&#x3C;/p&#x3E;
&#x3C;p&#x3E;And it might have been if it wasn&#x27;t for &#x3C;a href=&#x22;https://www.11ty.dev/docs/languages/webc/&#x22;&#x3E;WebC&#x3C;/a&#x3E; being so wonky. You see, I knew I wanted to have multiple OS9-like &#x22;windows&#x22; in the website&#x27;s layout. So I figured that, surely, WebC could let me make a &#x22;component&#x22; and make a UI that way and, I swear to god, I could not make it work that way.&#x3C;br /&#x3E;
It seems WebC is purely for &#x3C;strong&#x3E;W&#x3C;/strong&#x3E;eb &#x3C;strong&#x3E;C&#x3C;/strong&#x3E;omponents and nothing else, which itself is fine, but that wasn&#x27;t going to cut it.&#x3C;br /&#x3E;
I briefly experimented with a &#x3C;a href=&#x22;https://www.11ty.dev/docs/languages/liquid/#paired-shortcode&#x22;&#x3E;paired short code&#x3C;/a&#x3E;, but I wasn&#x27;t going to write HTML inside a JavaScript string. I wanted to have fun on this project.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;the-nitty-gritty&#x22;&#x3E;The nitty-gritty&#x3C;/h3&#x3E;
&#x3C;p&#x3E;So I switched to &#x3C;a href=&#x22;https://astro.build/&#x22;&#x3E;Astro&#x3C;/a&#x3E; whose concept of &#x3C;a href=&#x22;https://docs.astro.build/en/basics/astro-components/&#x22;&#x3E;components&#x3C;/a&#x3E; was closer to what I wanted to do here, and I already knew how to use it because &#x3C;a href=&#x22;https://erambert.me&#x22;&#x3E;erambert.me&#x3C;/a&#x3E; uses it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I will not do a play-by-play of the making of the website, because once the ball was rolling, most of my time was spent playing with UI ideas and using Astro&#x27;s &#x3C;a href=&#x22;https://docs.astro.build/en/guides/content-collections/&#x22;&#x3E;content collections&#x3C;/a&#x3E; such that building the whole website as a bunch of static pages didn&#x27;t take forever.&#x3C;br /&#x3E;
Don&#x27;t get me wrong, Astro is plenty fast as it is, not as fast as Eleventy but still fast!&#x3C;/p&#x3E;
&#x3C;p&#x3E;The &#x22;problem&#x22; is that I am playing with big numbers. Let&#x27;s think about them:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;3,942 themes&#x3C;/li&#x3E;
&#x3C;li&#x3E;868 authors&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;As it is, if we assume one page per scheme and one page per author (which would list all the themes for that author), we arrive at: &#x3C;strong&#x3E;3,942 + 868 = 4,810 pages&#x3C;/strong&#x3E;. Which isn&#x27;t terrible, but that&#x27;s already a lot of pages, and we&#x27;re not doing anything fancy with it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Let&#x27;s start being fancy, let&#x27;s add pagination and let&#x27;s say we want to show 51 themes per page. Where:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;&#x3C;em&#x3E;T&#x3C;/em&#x3E; is the number of themes in the set (3,942)&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;em&#x3E;A&#x3C;/em&#x3E; is the number of authors in the set (868)&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;em&#x3E;P&#x3C;/em&#x3E; is the page size (51)&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;js&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;totalPages&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;T&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;*&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;A&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;+&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; Math.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;ceil&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;T&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;P&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#99A0A6;--1:#616972&#x22;&#x3E;// 4,888 pages&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;That&#x27;s &#x3C;strong&#x3E;4,888 pages&#x3C;/strong&#x3E;! Except I then wanted to add some fancy things like an authors page &#x3C;em&#x3E;(A / 26 (for each letter in the alphabet))&#x3C;/em&#x3E;, that&#x27;s another ~33 pages. This gets us close to 5,000 pages. Which is fine, but it means every page better be really quick to generate in order for the build time to not balloon out-of-control.&#x3C;/p&#x3E;
&#x3C;p&#x3E;That&#x27;s where I had to be careful. I wanted the author pages to show all the themes made by a given author, which I naively implemented like this:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;typescript&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;export&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;getStaticPaths&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;async&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; () &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;authors&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;getCollection&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;authors&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; authors.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;map&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;a&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;props: { author: a },&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;params: {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;author: a.data.slug,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;},&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;};&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;satisfies&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;GetStaticPaths&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;author&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; Astro.props;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;themesByAuthor&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;getCollection&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;themes&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)).&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;filter&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;t&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; t.data.authors.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;some&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;a&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; a.id &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;===&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; author.id);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;Sure, this seems fine as it is. After all, it &#x22;only&#x22; takes ~30ms to run in development! But running our math from earlier, this will run for every single author page. Suddenly we&#x27;re looking at:&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;strong&#x3E;30ms &#xD7; 868 = 26,040 ms (26s)&#x3C;/strong&#x3E; &#x1F631;!&#x3C;/p&#x3E;
&#x3C;p&#x3E;After all, we&#x27;re iterating over the 3,942 schemes 868 times, this isn&#x27;t great!&#x3C;/p&#x3E;
&#x3C;p&#x3E;What&#x27;s the fix then?&#x3C;/p&#x3E;
&#x3C;p&#x3E;As it is almost always the case when it comes to performance: doing less work and only doing the hard work once! I took advantage of &#x3C;a href=&#x22;https://docs.astro.build/en/guides/content-collections/#defining-collection-references&#x22;&#x3E;Astro&#x27;s collection references&#x3C;/a&#x3E;. I first declare a reference for authors inside my &#x3C;code&#x3E;themes&#x3C;/code&#x3E; schema:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;ts&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;themes&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;defineCollection&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;({&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;loader: themesLoader,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;schema: z.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;object&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;({&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;name: z.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;string&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line highlight ins&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;   &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;authors: z.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#c2a8f3;--1:#613aa9&#x22;&#x3E;array&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#c2a8f3;--1:#613aa9&#x22;&#x3E;reference&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;authors&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;year: z.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;string&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;().&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;optional&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;mainThumbnail: z.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;string&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;thumbnails: z.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;array&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(z.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;string&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;()),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;archiveFile: z.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;string&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#99A0A6;--1:#616972&#x22;&#x3E;// ...&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;Which mean that I could simply call the &#x3C;a href=&#x22;https://docs.astro.build/en/reference/modules/astro-content/#getentries&#x22;&#x3E;getEntries&#x3C;/a&#x3E; method to get the authors of a given theme.&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;ts&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;export&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;getStaticPaths&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;async&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; () &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;authors&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;getCollection&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;authors&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; authors.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;map&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;a&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;props: { author: a },&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;params: {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;author: a.data.slug,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;},&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;};&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;satisfies&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;GetStaticPaths&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;author&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; Astro.props;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;themesByAuthor&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;getEntries&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(author.data.themes);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;Which, depending on the number of themes, takes ~10ms &#x3C;em&#x3E;at most&#x3C;/em&#x3E;, for most pages it takes less than 5ms! That is much better.&#x3C;/p&#x3E;
&#x3C;p&#x3E;By applying this technique, I managed to keep the build time of the site under control and Astro builds almost 5,000 pages with various queries between each other in less than 16s!&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/macthemes-build-time.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/macthemes-build-time.png&#x22; alt=&#x22;&#x26;quot;Astro&#x27;s CLI showing it built 4920 pages in 15.54s&#x26;quot;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;&#x22;Astro&#x27;s CLI showing it built 4920 pages in 15.54s&#x22;&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;getting-cute-with-it&#x22;&#x3E;Getting cute with it&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Like mentioned above, I knew I wanted to mimic a Mac OS 9 UI for the website. Now, I &#x3C;em&#x3E;could&#x3C;/em&#x3E; have just used images to make the UI... but where&#x27;s the fun in that?&#x3C;/p&#x3E;
&#x3C;p&#x3E;So of course I&#x27;ve used every CSS trick in the book to achieve the look. Let me go through some of the pieces of UI and explain how I re-created them.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;the-window-frame&#x22;&#x3E;The window frame&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/macthemes-garden-window.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/macthemes-garden-window.png&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;This is, obviously, a big part of the UI, so I wanted to be as close to the actual look of OS 9 as possible. Let&#x27;s take a simple, empty example:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;sandbox&#x22;&#x3E;
  &#x3C;div class=&#x22;macos9-window&#x22;&#x3E;
    &#x3C;div class=&#x22;macos9-window-titlebar&#x22;&#x3E; &#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;span class=&#x22;filler&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;span class=&#x22;title-text&#x22;&#x3E;Welcome!&#x3C;/span&#x3E; &#x3C;span class=&#x22;filler&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;/div&#x3E;
    &#x3C;div class=&#x22;macos9-window-body&#x22;&#x3E;
    &#xA0;
    &#x3C;/div&#x3E;
  &#x3C;/div&#x3E;
&#x3C;/div&#x3E;
&#x3C;p&#x3E;A lot of the styles involve using multiple box shadows to achieve the &#x22;broken border&#x22; effects in the different areas of the main UI chrome. Here is the style for the main window body (in white in the preview above):&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;css&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.macos9-window-body&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;border&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;solid&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--primary-black&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;box-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;rgb&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(from &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--primary-black&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) r g b / &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;40&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--primary-white&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--top-left-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--grays-600&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--bottom-right-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--primary-white&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;box-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--top-left-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--top-left-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--top-left-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--bottom-right-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--bottom-right-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--bottom-right-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-color&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--primary-white&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;h3 id=&#x22;the-title-bar&#x22;&#x3E;The title bar&#x3C;/h3&#x3E;
&#x3C;p&#x3E;That part was fun, there&#x27;s a lot going on so let&#x27;s take a look step by step. Here&#x27;s how it looks and the HTML markup:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;sandbox&#x22;&#x3E;
  &#x3C;div class=&#x22;macos9-window&#x22;&#x3E;
    &#x3C;div class=&#x22;macos9-window-titlebar&#x22;&#x3E; &#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;span class=&#x22;filler&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;span class=&#x22;title-text&#x22;&#x3E;Welcome!&#x3C;/span&#x3E; &#x3C;span class=&#x22;filler&#x22;&#x3E;&#x3C;/span&#x3E;
         &#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E; 
        &#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E;
      &#x3C;/div&#x3E;
  &#x3C;/div&#x3E;
&#x3C;/div&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;html&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;macos9-window-titlebar&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;button&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;button close&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;data-action&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;close&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;button-dots&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;button&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;filler&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;title-text&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;Welcome!&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;filler&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;button&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;button zoom&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;data-action&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;zoom&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;button-dots&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;button&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;button&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;button collapse&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;data-action&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;collapse&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;button-dots&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;button&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;The &#x22;stripes&#x22; pattern is done using a repeating CSS gradient and two pseudo-elements on each side with a slightly different gradient:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;css&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.macos9-window-titlebar&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;span&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.filler&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;flex&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-color&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#dddddd&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-image&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;linear-gradient&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#ffffff&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#ffffff&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;50&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#777777&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;50&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#777777&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-repeat&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;repeat&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-size&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;100&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;2&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;height&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;12&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;position&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;relative&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;amp;::before,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;amp;::after {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;content&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;position&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;absolute&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;width&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-size&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;100&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;2&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;display&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;block&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;amp;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;::before&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;left&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;top&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;bottom&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-image&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;linear-gradient&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#fff&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#fff&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;50&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#cccccc&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;50&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#cccccc&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;border-bottom&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;solid&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#cccccc&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;amp;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;::after&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;right&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;top&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;bottom&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-image&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;linear-gradient&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#ccc&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#ccc&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;50&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#777777&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;50&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#777777&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;We then have the window buttons which are...you guessed it, a lot of box-shadows and borders put together:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;sandbox&#x22;&#x3E;
  &#x3C;div class=&#x22;macos9-window&#x22;&#x3E;
    &#x3C;div class=&#x22;macos9-window-titlebar&#x22;&#x3E; &#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;/div&#x3E;
  &#x3C;/div&#x3E;
&#x3C;/div&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;css&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.macos9-window-titlebar&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;button&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;appearance&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;none&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;border&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;none&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;height&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;13&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;width&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;13&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;transparent&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-image&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;linear-gradient&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;135&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;deg&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#9a9a9a&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#f1f1f1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;100&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-size&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;9&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;9&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-position&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;center&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;box-shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;inset&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--grays-700&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;inset&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--primary-white&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;inset&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;2&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--primary-black&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;inset&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;3&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;3&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--primary-white&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;inset&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-3&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;-3&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--grays-700&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;position&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;relative&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;z-index&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;amp;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;active&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;::before {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;content&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;inset&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;2&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-image&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;linear-gradient&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;135&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;deg&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;rgba&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;53&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;53&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;53&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0.8&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;rgba&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;156&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;156&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;156&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0.8&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;100&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;%&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;display&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;block&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;position&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;absolute&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;z-index&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.macos9-window-titlebar&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;button&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.button-dots&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;position&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;absolute&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;inset&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;display&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;block&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;amp;::before {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;content&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;position&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;absolute&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;top&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;right&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;width&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;height&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-color&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#cccccc&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;amp;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;::after&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;content&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;position&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;absolute&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;bottom&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;left&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;width&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;height&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;background-color&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#cccccc&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;Oh, and there is also a neat trick: I&#x27;m using &#x3C;code&#x3E;:has()&#x3C;/code&#x3E; to sometimes re-align the title so it&#x27;s actually visually centered when there is an uneven number of buttons on each side:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;css&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.macos9-window-titlebar:has&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.button.close&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.button.zoom&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.button.close&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.button.close&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;+&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.filler&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;padding-left&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;calc&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;13&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;px&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;+&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;var&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;--macos9-window-titlebar-gap&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;));&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;h3 id=&#x22;buttons&#x22;&#x3E;Buttons&#x3C;/h3&#x3E;
&#x3C;p&#x3E;This is the part of the design that made me question my sanity and my commitment to the bit. Let&#x27;s take a look at a simple button:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;sandbox sandbox-button&#x22;&#x3E;
&#x3C;a class=&#x22;os9-button&#x22; asbutton type=&#x22;submit&#x22;&#x3E;&#x3C;div class=&#x22;grid&#x22;&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;01&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;02&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;03&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;04&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;05&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;06&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;07&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;08&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;09&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;10&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;11&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;12&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;13&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;14&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;15&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;16&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;17&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;18&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;19&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;20&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;21&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;22&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;23&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;24&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;25&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;26&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;27&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;28&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;29&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;30&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;31&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;32&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;33&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;34&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;35&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;36&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;37&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;shadow&#x22; data-n=&#x22;38&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;bgd&#x22; data-n=&#x22;1&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;bgd&#x22; data-n=&#x22;2&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;bgd&#x22; data-n=&#x22;3&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;bgd&#x22; data-n=&#x22;4&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;label&#x22;&#x3E;Press me!&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/a&#x3E;
&#x3C;/div&#x3E;
&#x3C;p&#x3E;Looks simple enough, right? Well. How do you preserve the pixelated look in CSS without using images? Why, you go insane and draw the pixels yourself using CSS Grid areas of course! This was a &#x3C;a href=&#x22;https://codepen.io/wavebeem/pen/VYYLqJv?editors=1100&#x22;&#x3E;suggestion&#x3C;/a&#x3E; from &#x3C;a href=&#x22;https://wavebeem.com&#x22;&#x3E;Sage&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;This requires some planning because CSS Grid areas have to be rectangular. That&#x27;s when I went to Photoshop and drew a bunch of colored rectangles for each area with unique colors:&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/macthemes-button-grid.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/macthemes-button-grid.png&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;That&#x27;s 38 areas for the inner/outer shadows to cover, as well as 4 areas for the plain background! It&#x27;s easy enough to just generate that using JSX, we take care to add a &#x3C;code&#x3E;data-n&#x3C;/code&#x3E; attribute which will help us target the areas in CSS:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;tsx&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;a&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;className&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;os9-button&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;className&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;grid&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{Array.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;({ length: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;38&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; }).&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;map&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;_&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;index&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;key&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{index}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;className&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;shadow&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;data-n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;String&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(index &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;+&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;).&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;padStart&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;2&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;0&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;/&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;))}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;className&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;bgd&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;data-n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;1&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;className&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;bgd&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;data-n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;2&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;className&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;bgd&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;data-n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;3&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;className&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;bgd&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;data-n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;4&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;className&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;label&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;{children}&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;a&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;Then, we have to use Sass to create the necessary selectors:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;scss&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;@use&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;sass:math&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;@for&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;$i&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;through&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;38&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;$n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;$i&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;@if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;$n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;10&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;$n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;#{$n}&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.shadow&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;[&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;data-n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;#{$n}&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;] {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;grid-area&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: s&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;#{$n}&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;@for&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;$i&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;through&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;4&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.bgd&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;[&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;data-n&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;#{$i}&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;] {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;grid-area&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: bg&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;#{$i}&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;Then...we &#x22;draw&#x22; our CSS areas with code:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;scss&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;.grid&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;display&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;grid&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;grid-template-areas&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;... ... s01 s02 s02 s02 s03 ... ...&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;... s04 s05 s06 s06 s06 s07 s08 ...&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;s09 s10 s38 s11 s11 s11 s12 s13 s14&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;s15 s16 s17 s17 bg1 bg1 s18 s19 s20&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;s15 s16 s37 bg2 txt bg3 s18 s19 s20&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;s15 s16 s37 bg2 bg4 s21 s18 s19 s20&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;s22 s23 s24 s25 s26 s26 s27 s28 s29&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;... s30 s31 s32 s32 s32 s32 s33 ...&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;... ... s34 s35 s35 s35 s36 ... ...&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;grid-template-columns&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;repeat&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;4&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;max-content&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;fr&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;repeat&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;5&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;max-content&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;grid-template-rows&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;repeat&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;4&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;max-content&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;fr&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;repeat&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;4&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;max-content&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;Yes, this took a while and multiple tries to get right LMAO. The full &#x3C;a href=&#x22;https://github.com/eramdam/macthemes.garden/blob/main/src/components/OS9Button.scss&#x22;&#x3E;stylesheet is here&#x3C;/a&#x3E; if you&#x27;re curious.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;random-tidbits&#x22;&#x3E;Random tidbits&#x3C;/h3&#x3E;
&#x3C;h3 id=&#x22;window-controls&#x22;&#x3E;Window controls&#x3C;/h3&#x3E;
&#x3C;p&#x3E;The windows are actually interactive! You can &#x22;zoom&#x22; (expand) the main window and collapse it by clicking the right button/double-clicking the title bar!&#x3C;/p&#x3E;
&#x3C;div class=&#x22;sandbox&#x22;&#x3E;
  &#x3C;div class=&#x22;macos9-window&#x22; id=&#x22;demo-window&#x22;&#x3E;
    &#x3C;div class=&#x22;macos9-window-titlebar&#x22;&#x3E; &#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;span class=&#x22;filler&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;span class=&#x22;title-text&#x22;&#x3E;Welcome!&#x3C;/span&#x3E; &#x3C;span class=&#x22;filler&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E;&#x3C;span class=&#x22;button-dots&#x22;&#x3E;&#x3C;/span&#x3E; &#x3C;/div&#x3E;
    &#x3C;div class=&#x22;macos9-window-body&#x22;&#x3E;
      Play with the buttons!
    &#x3C;/div&#x3E;
  &#x3C;/div&#x3E;
&#x3C;/div&#x3E;

&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;js&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;windowElement&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; document.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;querySelector&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x27;#demo-window&#x27;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;windowElement.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;querySelectorAll&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;button&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;).&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;forEach&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;((&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;button&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (button.dataset.action &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;===&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;collapse&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;titlebar&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; windowElement.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;querySelector&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;.macos9-window-titlebar&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (titlebar) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;titlebar.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;addEventListener&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;dblclick&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;e&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (e.target &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;instanceof&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;HTMLButtonElement&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;windowElement.classList.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toggle&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;collapsed&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;window.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;getSelection&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;()?.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;empty&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;();&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;button.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;addEventListener&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;click&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, () &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;action&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; button.dataset.action;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (action &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;===&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;collapse&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;windowElement.classList.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toggle&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;collapsed&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;} &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;else&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (action &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;===&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;zoom&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;windowElement.classList.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toggle&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;zoomed&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;h3 id=&#x22;open-graph-images&#x22;&#x3E;Open Graph images&#x3C;/h3&#x3E;
&#x3C;p&#x3E;I could have taken the easy route when making the open graph images for each theme and simply dropped a PNG of the main window, something like this:&#x3C;/p&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;
  &#x3C;picture&#x3E;
    &#x3C;source srcset=&#x22;https://damien.zone/img/blog/macthemes-embed-v1-dark.png&#x22; media=&#x22;(prefers-color-scheme: dark)&#x22; type=&#x22;image/png&#x22;&#x3E;&#x3C;/source&#x3E;
    &#x3C;source srcset=&#x22;https://damien.zone/img/blog/macthemes-embed-v1-light.png&#x22; type=&#x22;image/png&#x22;&#x3E;&#x3C;/source&#x3E;
    &#x3C;img src=&#x22;https://damien.zone/img/blog/macthemes-embed-v1-light.png&#x22; alt=&#x22;Discord embed with a simple window without any background&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;437&#x22; /&#x3E;
  &#x3C;/picture&#x3E;
&#x3C;/figure&#x3E;
&#x3C;p&#x3E;This is very cute in apps like Discord, but looks terrible about everywhere else because of the wrong aspect ratio and the non-support of alpha channels.&#x3C;/p&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;
  &#x3C;picture&#x3E;
    &#x3C;source srcset=&#x22;https://damien.zone/img/blog/macthemes-embed-v1-bsky-dark.png&#x22; media=&#x22;(prefers-color-scheme: dark)&#x22; type=&#x22;image/png&#x22;&#x3E;&#x3C;/source&#x3E;
    &#x3C;source srcset=&#x22;https://damien.zone/img/blog/macthemes-embed-v1-bsky-light.png&#x22; type=&#x22;image/png&#x22;&#x3E;&#x3C;/source&#x3E;
    &#x3C;img src=&#x22;https://damien.zone/img/blog/macthemes-embed-v1-bsky-light.png&#x22; alt=&#x22;Bluesky embed with a simple window without any background&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;437&#x22; /&#x3E;
  &#x3C;/picture&#x3E;
&#x3C;/figure&#x3E;
&#x3C;p&#x3E;So I took another approach:&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;https://macthemes.garden/themes-opengraph/13d46b4752aa-Monkey-Paradise.png&#x22;&#x3E;&#x3C;img src=&#x22;https://macthemes.garden/themes-opengraph/13d46b4752aa-Monkey-Paradise.png&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;But, obviously, doing that kind of compositing manually would be a terrible idea, and I&#x27;m not good enough with ImageMagick, so I ended up using Vercel&#x27;s &#x3C;a href=&#x22;https://github.com/vercel/satori&#x22;&#x3E;satori&#x3C;/a&#x3E; to lay the two images out and generate an image for every single theme:&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;tsx&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;type&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { InferEntrySchema } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;astro:content&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; satori &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;satori&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; sharp &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;sharp&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;export&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;async&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;function&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;generateOpenGraphImageForTheme&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;theme&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;InferEntrySchema&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;themes&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;let&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; blurredImageData&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;Buffer&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;|&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;undefined&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;margin&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;20&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;imageDimension&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;width: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1200&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;height: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;630&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;};&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;if&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (theme.thumbnails.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;length&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;blurredImageData &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;sharp&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;public/&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;+&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; theme.thumbnails[&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;1&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;])&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;resize&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(imageDimension.width, imageDimension.height, {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;fit: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;cover&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;position: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;top&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;})&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;blur&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;5&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toBuffer&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;();&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;mainThumbnailSharp&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;sharp&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;public&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;+&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; theme.mainThumbnail);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;mainThumbnail&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; mainThumbnailSharp.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;png&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;().&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toBuffer&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;();&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;svg&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;satori&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;style&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{{&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;display: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;flex&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;alignItems: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;center&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;justifyItems: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;center&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;width: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;100%&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;height: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;100%&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;position: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;relative&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;backgroundColor: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;white&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{blurredImageData &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;&#x26;amp;&#x26;amp;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;img&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;src&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toArrayBuffer&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(blurredImageData)}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;style&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{{&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;            &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;position: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;absolute&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;            &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;filter: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;brightness(40%)&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;            &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;inset: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;/&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;)}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;img&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;src&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toArrayBuffer&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(mainThumbnail)}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;style&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{{&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;padding: margin,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;width: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;100%&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;height: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;100%&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;boxSizing: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;border-box&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;objectFit: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;contain&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;          &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;objectPosition: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;center center&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;        &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;/&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;div&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;width: imageDimension.width,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;height: imageDimension.height,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;fonts: [],&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;},&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;sharp&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(Buffer.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(svg));&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;function&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toArrayBuffer&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;buffer&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;Buffer&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;arrayBuffer&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;ArrayBuffer&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(buffer.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;length&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;view&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;Uint8Array&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(arrayBuffer);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;for&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; (&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;let&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; i &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;0&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;; i &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; buffer.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;length&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;++&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;i) {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;view[i] &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; buffer[i];&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; arrayBuffer;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;I then put together a &#x3C;a href=&#x22;https://github.com/eramdam/macthemes.garden/blob/7a8983b64114d6305eb906169aaf64b6005321a5/scripts/opengraph-images.ts&#x22;&#x3E;script&#x3C;/a&#x3E; to process all the images by spawning multiple process, the whole script takes ~2min30 to run on my M1 Max Mac Studio and generate ~3900 images.&#x3C;/p&#x3E;
&#x3C;p&#x3E;As a bonus, these images will also be used by the Mac Themes Bot when available going forward.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;whats-next&#x22;&#x3E;What&#x27;s next&#x3C;/h2&#x3E;
&#x3C;p&#x3E;I don&#x27;t know how long it will take, but I want to continue/finish &#x22;recording&#x22; the schemes I have access to. Hopefully I am done before next year lolsob. You should subscribe to the &#x3C;a href=&#x22;https://macthemes.garden/feed.xml&#x22;&#x3E;RSS feed&#x3C;/a&#x3E; to see those as I update them!&#x3C;/p&#x3E;
&#x3C;p&#x3E;Apart from that, I have a bunch of ideas:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;a &#x22;search by color&#x22; feature&#x3C;/li&#x3E;
&#x3C;li&#x3E;a way to see/showcase the custom icons contained in each scheme when applicable. There are some gems in there, trust me!&#x3C;/li&#x3E;
&#x3C;li&#x3E;Somehow, find a way to hook the site into &#x3C;a href=&#x22;https://infinitemac.org/&#x22;&#x3E;InfiniteMac&#x3C;/a&#x3E; to quickly view a scheme &#x22;live&#x22;&#x3C;/li&#x3E;
&#x3C;li&#x3E;a user-submitted gallery of old Macs running the schemes from the site. Hit me up if this is something you&#x27;d want to participate in :)&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;That&#x27;s all, folks, have a good life.&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;


&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;or vice versa, I honestly do not remember nor do I care to check the Git history. &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/introducing-mac-themes-garden&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Modding Balatro on PC to add touch controls</title>
          <link href="https://damien.zone/modding-balatro-on-pc-to-add-touch-controls" rel="alternate"/>
          <id>https://damien.zone/modding-balatro-on-pc-to-add-touch-controls</id>
          <published>2025-03-02T03:06:14Z</published>
          <updated>2025-05-21T06:08:43Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/sticky-fingers-hero.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/sticky-fingers-hero.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;em&#x3E;TL;DR: I&#x27;ve made a Balatro mod that adds the touch controls of the iOS version on PC. It&#x27;s called &#x22;Sticky Fingers&#x22; and is available to &#x3C;a href=&#x22;https://github.com/eramdam/sticky-fingers&#x22;&#x3E;download on GitHub&#x3C;/a&#x3E;! This post will is mostly about the process of making the mod itself.&#x3C;/em&#x3E;&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;how-i-got-here&#x22;&#x3E;How I got here&#x3C;/h2&#x3E;
&#x3C;p&#x3E;If you&#x27;re reading this, I probably do not need to explain &#x3C;a href=&#x22;https://www.playbalatro.com/&#x22;&#x3E;Balatro&#x3C;/a&#x3E; to you. To say I got &#x3C;em&#x3E;into&#x3C;/em&#x3E; this game would be an understatement. According to Steam, I&#x27;ve spent &#x3C;strong&#x3E;210 hours&#x3C;/strong&#x3E; playing it last year and I expect to spend half of that amount playing it in the next year. The game&#x27;s good, turns out.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Balatro released on PC in February 2024, Mac in March, and got an official mobile port in September of the same year.&#x3C;br /&#x3E;
And that mobile port is great! Great use of the haptic engine and most importantly&#x2026; great touch controls!&#x3C;/p&#x3E;
&#x3C;p&#x3E;If you don&#x27;t know what I&#x27;m talking about, here&#x27;s a little recording showing them off:&#x3C;/p&#x3E;
&#x3C;figure data-type=&#x22;video&#x22;&#x3E;
&#x3C;video src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-touch-ios.mp4&#x22; poster=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-touch-ios-poster.webp?v=a2e286656790&#x22; playsinline controls preload=&#x22;none&#x22;&#x3E;&#x3C;/video&#x3E;
&#x3C;figcaption&#x3E;
Balatro on iOS and its touch controls to buy/sell/use cards
&#x3C;/figcaption&#x3E;
&#x3C;/figure&#x3E;
&#x3C;p&#x3E;After playing the game on iOS a bunch, I&#x27;ve come to really like those controls and would often miss them when playing on my Mac.&#x3C;/p&#x3E;
&#x3C;p&#x3E;So I did the reasonable thing&#x2026; Hoping that &#x3C;em&#x3E;someone&#x3C;/em&#x3E; ported those controls to the desktop version of Balatro.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Until I got fed up with waiting and asked myself: &#x2728; &#x22;How hard could it be, really?&#x22; &#x2728;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Not &#x3C;em&#x3E;that&#x3C;/em&#x3E; hard, but not easy either, it turns out!&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;background&#x22;&#x3E;Background&#x3C;/h2&#x3E;
&#x3C;p&#x3E;If you are unaware, Balatro is a game written using the &#x3C;a href=&#x22;https://love2d.org/&#x22;&#x3E;L&#xD6;VE&#x3C;/a&#x3E; framework in &#x3C;a href=&#x22;https://www.lua.org/&#x22;&#x3E;Lua&#x3C;/a&#x3E; and more importantly&#x2026; the code of the game is available on the file system when you buy it! All of it, neither obfuscated nor minified! This is, obviously, very convenient when it comes to making mods (&#x3C;a href=&#x22;https://github.com/jie65535/awesome-balatro&#x22;&#x3E;of which there are many&#x3C;/a&#x3E;), and it greatly simplified what I wanted to do.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The plan was &#x22;simple&#x22;:&#x3C;/p&#x3E;
&#x3C;ol&#x3E;
&#x3C;li&#x3E;get the Balatro PC/Mac source code&#x3C;/li&#x3E;
&#x3C;li&#x3E;get the Balatro iOS source code&#x3C;/li&#x3E;
&#x3C;li&#x3E;compare the two file-by-file and figure out what pieces of code I needed to &#x22;transplant&#x22; into the PC version to get the drag&#x27;n&#x27;drop controls working.&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;h2 id=&#x22;getting-the-balatro-pcmac-source-code&#x22;&#x3E;Getting the Balatro PC/Mac source code&#x3C;/h2&#x3E;
&#x3C;p&#x3E;This is pretty easy, just open the local folder of the game on Steam, open Balatro.exe/Balatro.app and the &#x3C;code&#x3E;Balatro.love&#x3C;/code&#x3E; file is an archive that can be extracted/recompressed pretty easily!&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/balatro-folder-dark.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-folder-dark.webp&#x22; alt=&#x22;A Finder window on macOS showing the content of Balatro.love&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;A Finder window on macOS showing the content of Balatro.love&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;getting-the-balatro-ios-source-code&#x22;&#x3E;Getting the Balatro iOS source code&#x3C;/h2&#x3E;
&#x3C;p&#x3E;This proved more difficult&#x2026;but only because I accidentally made my life harder &#x1F605;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;what-i-should-have-done&#x22;&#x3E;What I should have done&#x3C;/h3&#x3E;
&#x3C;p&#x3E;I &#x3C;em&#x3E;should&#x3C;/em&#x3E; have realized that &#x3C;a href=&#x22;https://apps.apple.com/us/app/balatro/id6502451661&#x22;&#x3E;Balatro+&#x3C;/a&#x3E; (Apple Arcade version of the game) is a universal macOS/iPadOS/iOS app. Meaning that I could just download the game on my Mac and&#x2026;open the &#x3C;code&#x3E;.app&#x3C;/code&#x3E; package and &#x3C;em&#x3E;voil&#xE0;&#x3C;/em&#x3E;! The iOS source code, easily accessible!&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/balatro-ios-apple-arcade.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-ios-apple-arcade.webp&#x22; alt=&#x22;A Finder window on macOS showing the content of Balatro+ (Balatro.app)&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;A Finder window on macOS showing the content of Balatro+ (Balatro.app)&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;what-i-did-instead-because-i-didnt-know-any-better&#x22;&#x3E;What I did instead because I didn&#x27;t know any better&#x3C;/h3&#x3E;
&#x3C;p&#x3E;So here&#x27;s how I managed to grab the source of the iOS port, which required getting the &#x3C;code&#x3E;.ipa&#x3C;/code&#x3E; file for the app onto my Mac:&#x3C;/p&#x3E;
&#x3C;ol&#x3E;
&#x3C;li&#x3E;Install &#x3C;a href=&#x22;https://imazing.com/&#x22;&#x3E;iMazing&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;Plug my iPhone to my Mac&#x3C;/li&#x3E;
&#x3C;li&#x3E;Click &#x3C;em&#x3E;Manage Apps&#x3C;/em&#x3E;&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/balatro-imazing.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-imazing.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;ol start=&#x22;4&#x22;&#x3E;
&#x3C;li&#x3E;Go to the &#x3C;em&#x3E;Library&#x3C;/em&#x3E; tab&#x3C;/li&#x3E;
&#x3C;li&#x3E;Find Balatro in the list&#x3C;/li&#x3E;
&#x3C;li&#x3E;Select &#x22;Export .IPA&#x22;&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/balatro-imazing-library.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-imazing-library.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;ol start=&#x22;7&#x22;&#x3E;
&#x3C;li&#x3E;Decompress the &#x3C;code&#x3E;.ipa&#x3C;/code&#x3E; file, since &#x3C;code&#x3E;.ipa&#x3C;/code&#x3E; files are just fancy archives&#x3C;/li&#x3E;
&#x3C;li&#x3E;Go to &#x3C;code&#x3E;Payload/Balatro.app/game&#x3C;/code&#x3E; and&#x2026;&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;p&#x3E;Tada! The files are there!&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/balatro-ios-folder.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-ios-folder.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;comparing-the-two-codebases&#x22;&#x3E;Comparing the two codebases&#x3C;/h2&#x3E;
&#x3C;p&#x3E;This part wasn&#x27;t complicated in itself, it just took a long time.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I opened the two folders in a Visual Studio Code workspace and went through most of the files that seemed relevant and compared them against their iOS counterpart.&#x3C;br /&#x3E;
Then, every time I found a bit of code that seemed useful, I would copy it over the desktop file and launch the game until I got what I wanted.&#x3C;/p&#x3E;


  &#x3C;strong&#x3E;
    Special trick that helped me a lot with this
  &#x3C;/strong&#x3E;

&#x3C;p&#x3E;So you know how I said earlier that the source code of Balatro is just &#x3C;em&#x3E;there&#x3C;/em&#x3E; in an &#x22;archive&#x22;? Well, on macOS, you can abuse symlinks to have &#x3C;code&#x3E;Balatro.love&#x3C;/code&#x3E; point to a modified copy of the code, which makes it easy to quickly test changes!&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/balatro-mac-symlink.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-mac-symlink.webp&#x22; alt=&#x22;A Finder window inside the Balatro game files with &#x60;Balatro.love&#x60; being a symlink&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;A Finder window inside the Balatro game files with &#x60;Balatro.love&#x60; being a symlink&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;

&#x3C;p&#x3E;And I did get what I wanted!&#x3C;/p&#x3E;
&#x3C;blockquote class=&#x22;mastodon-embed&#x22; data-embed-url=&#x22;https://social.erambert.me/@eramdam/113813401719828118/embed&#x22; style=&#x22;background:#FCF8FF;border-radius:8px;border:1px solid #C9C4DA;margin:0;max-width:540px;min-width:270px;overflow:hidden;padding:0&#x22;&#x3E; &#x3C;a href=&#x22;https://social.erambert.me/@eramdam/113813401719828118&#x22; target=&#x22;_blank&#x22; style=&#x22;align-items:center;color:#1C1A25;display:flex;flex-direction:column;font-family:system-ui, -apple-system, BlinkMacSystemFont, &#x27;Segoe UI&#x27;, Oxygen, Ubuntu, Cantarell, &#x27;Fira Sans&#x27;, &#x27;Droid Sans&#x27;, &#x27;Helvetica Neue&#x27;, Roboto, sans-serif;font-size:14px;justify-content:center;letter-spacing:0.25px;line-height:20px;padding:24px;text-decoration:none&#x22;&#x3E;  &#x3C;div style=&#x22;color:#787588;margin-top:16px&#x22;&#x3E;Post by @eramdam@erambert.me&#x3C;/div&#x3E; &#x3C;div style=&#x22;font-weight:500&#x22;&#x3E;View on Mastodon&#x3C;/div&#x3E; &#x3C;/a&#x3E; &#x3C;/blockquote&#x3E; 
&#x3C;h2 id=&#x22;actually-turn-this-into-a-mod&#x22;&#x3E;Actually turn this into a mod&#x3C;/h2&#x3E;
&#x3C;p&#x3E;After a while, I had a local-only Git repo called &#x3C;code&#x3E;balatro-touch-desktop&#x3C;/code&#x3E; which house the desktop files that I modified by hand. This was very convenient to quickly iterate/see what I actually changed between the original code and my &#x22;mod&#x22; but, well, it wasn&#x27;t exactly a real Balatro mod. The best I could do was generate a &#x3C;code&#x3E;.patch&#x3C;/code&#x3E; file that could be applied to the vanilla game.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I do not intend for this article to be a &#x22;how to make a Balatro mod&#x22; tutorial&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E; but, at the very high level, I needed a way to turn my &#x3C;a href=&#x22;https://github.com/eramdam/sticky-fingers/blob/main/touch-mode/touch-mode.patch&#x22;&#x3E;Git patch&#x3C;/a&#x3E; into a proper mod that used &#x3C;a href=&#x22;https://github.com/ethangreen-dev/lovely-injector&#x22;&#x3E;lovely-injector&#x3C;/a&#x3E; to modify the games&#x27; files.&#x3C;/p&#x3E;
&#x3C;p&#x3E;If you&#x27;re unfamiliar, Lovely&#x27;s README file has &#x3C;a href=&#x22;https://github.com/ethangreen-dev/lovely-injector?tab=readme-ov-file#patches&#x22;&#x3E;examples of patches&#x3C;/a&#x3E; that can be applied.&#x3C;/p&#x3E;
&#x3C;p&#x3E;On paper, this seemed simple enough, the problem was that my changes were precise/small enough that it was very tricky to write a patch by hand. Adding new functions entirely is straightforward, but adding and extra &#x3C;code&#x3E;elseif&#x3C;/code&#x3E; clause 3 levels deep? That drove me nuts, and it wouldn&#x27;t even work because I kept generating invalid Lua files &#x1FAE0;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;This is when &#x3C;a href=&#x22;https://github.com/a-e-m&#x22;&#x3E;Amy&#x3C;/a&#x3E; essentially saved my butt and wrote a &#x3C;a href=&#x22;https://github.com/a-e-m/lovely-differ&#x22;&#x3E;tool&#x3C;/a&#x3E; that did exactly what I wanted! Turn my Git diff into a &#x3C;code&#x3E;lovely.toml&#x3C;/code&#x3E; patch file!&#x3C;/p&#x3E;
&#x3C;p&#x3E;From that point on, putting the mod together was relatively simple, and there I had it! My mod in the &#x3C;code&#x3E;Mods&#x3C;/code&#x3E; section.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/balatro-touch-mods-list.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-touch-mods-list.webp&#x22; alt=&#x22;The Steamodded &#x27;Mods&#x27; window with my mod in there&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;The Steamodded &#x27;Mods&#x27; window with my mod in there&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;improving-on-it&#x22;&#x3E;Improving on it&#x3C;/h2&#x3E;
&#x3C;p&#x3E;After that, I had the perfect excuse to play Balatro had to test the mod to make sure nothing crashed or behaved weirdly. Thankfully, everything worked just fine! The only &#x22;issue&#x22; was that the &#x22;Sell&#x22; target for jokers was &#x3C;em&#x3E;way&#x3C;/em&#x3E; too close to the main joker area, which made it too easy to accidentally sell a joker when re-arranging them quickly (ask me how I know).&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/balatro-touch-og-sell-zone.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-touch-og-sell-zone.webp&#x22; alt=&#x22;Balatro with the touch control mod, showing the default sell zone for jokers (in the top right of the game&#x27;s UI)&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Balatro with the touch control mod, showing the default sell zone for jokers (in the top right of the game&#x27;s UI)&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Thankfully, smods provides &#x3C;a href=&#x22;https://github.com/Steamodded/smods/wiki/Mod-functions#modconfig_tab&#x22;&#x3E;a built-in way to make a mod configurable&#x3C;/a&#x3E; so after an hour or two, I managed to &#x3C;a href=&#x22;https://github.com/eramdam/sticky-fingers/commit/b6c2bf5590470a30b36d66ad35d08a899b984a11&#x22;&#x3E;make an option&#x3C;/a&#x3E; (turned on by default) that moved the sell target further to prevent this from happening again.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/balatro-mod-option.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-mod-option.webp&#x22; alt=&#x22;The options tab of the mod, with &#x26;quot;Harder Joker sell target&#x26;quot; checked.&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;The options tab of the mod, with &#x22;Harder Joker sell target&#x22; checked.&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/balatro-touch/balatro-harder-sell.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/balatro-touch/balatro-harder-sell.webp&#x22; alt=&#x22;Balatro with the touch control mod, showing the &#x27;harder&#x27; sell zone for jokers (in the middle right of the game&#x27;s UI)&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Balatro with the touch control mod, showing the &#x27;harder&#x27; sell zone for jokers (in the middle right of the game&#x27;s UI)&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;releasing-the-mod&#x22;&#x3E;Releasing the mod&#x3C;/h2&#x3E;
&#x3C;p&#x3E;And there you have it! The mod is available on GitHub, as I&#x27;m writing this, I just updated it for compatibility with Balatro 1.0.1o.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://github.com/eramdam/sticky-fingers&#x22;&#x3E;https://github.com/eramdam/sticky-fingers&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Let me know if you enjoy it and/or have any issues with it!&#x3C;/p&#x3E;
&#x3C;p&#x3E;Bye!&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;the &#x3C;a href=&#x22;https://github.com/Steamodded/smods/wiki/Your-First-Mod&#x22;&#x3E;smods wiki&#x3C;/a&#x3E; is better for this &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/modding-balatro-on-pc-to-add-touch-controls&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Site update (january 2025)</title>
          <link href="https://damien.zone/site-update-january-2025" rel="alternate"/>
          <id>https://damien.zone/site-update-january-2025</id>
          <published>2025-01-20T09:50:43Z</published>
          <updated></updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;I&#x27;ve done some tweaks to the layout of the site around &#x3C;a href=&#x22;https://damien.zone&#x22;&#x3E;links&#x3C;/a&#x3E;, &#x3C;code&#x3E;code bits&#x3C;/code&#x3E; and other things I&#x27;m probably forgetting. The &#x3C;a href=&#x22;/blog&#x22;&#x3E;/blog&#x3C;/a&#x3E; page looks a bit more feed-like now as well.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Oh, yeah, and the blog has &#x3C;a href=&#x22;https://nex-3.com/blog/a-non-technical-intro-to-webmentions/&#x22;&#x3E;Webmentions&#x3C;/a&#x3E; support now! Meaning that if you mention my blog from your website or on social media (Bluesky, Mastodon), it should appear alongside comments on the blog.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;strong&#x3E;Also&#x3C;/strong&#x3E;, if you had my button on your website, and you included the direct link, please update it like so, replacing &#x3C;code&#x3E;https://files.damien.zone/88x31_damien.png&#x3C;/code&#x3E; with &#x3C;code&#x3E;https://damien.zone/public/88x31_damien.png&#x3C;/code&#x3E;. I have set up a redirection on my server, so existing buttons don&#x27;t break, but ideally that&#x27;d be temporary &#x1F605;&#x3C;/p&#x3E;
&#x3C;p&#x3E;That&#x27;s all!&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/site-update-january-2025&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>website creatures</title>
          <link href="https://damien.zone/website-creatures" rel="alternate"/>
          <id>https://damien.zone/website-creatures</id>
          <published>2025-01-11T03:01:47Z</published>
          <updated></updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/websitecreatures/IMG_8615.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/websitecreatures/IMG_8615.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;A good creature in plush form is the mark of a, if not good, fine website imo&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/website-creatures&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>New year, new site!</title>
          <link href="https://damien.zone/new-year-new-site" rel="alternate"/>
          <id>https://damien.zone/new-year-new-site</id>
          <published>2025-01-07T02:07:13Z</published>
          <updated></updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;figure data-type=&#x22;image&#x22;&#x3E;
&#x3C;picture&#x3E;
&#x3C;source srcset=&#x22;https://damien.zone/img/blog/damienzone25/damien-zone-2025-dark.webp&#x22; media=&#x22;(prefers-color-scheme: dark)&#x22;&#x3E;&#x3C;/source&#x3E;
&#x3C;img srcset=&#x22;https://damien.zone/img/blog/damienzone25/damien-zone-2025.webp&#x22; /&#x3E;
&#x3C;/picture&#x3E;
&#x3C;/figure&#x3E;
&#x3C;p&#x3E;Here it is, the new year! I can&#x27;t say I&#x27;m especially overjoyed about it, but I&#x27;m also fine with leaving 2024 behind, so... you know.&#x3C;/p&#x3E;
&#x3C;p&#x3E;At any rate, as you (maybe) can see, this website got a bit of an overhaul!&#x3C;br /&#x3E;
I spent a few days during my winter break re-implementing it using &#x3C;a href=&#x22;https://www.11ty.dev/&#x22;&#x3E;Eleventy&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://bearblog.dev/&#x22;&#x3E;Bearblog&#x3C;/a&#x3E; served me well for the past few months, but I knew that, at some point, I&#x27;d want to control everything... so here we are.&#x3C;/p&#x3E;
&#x3C;p&#x3E;While the goal of this migration was to make a 1:1 copy of the way the site looked on Bear, I couldn&#x27;t help myself and made a few tweaks here and there.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;damienzone-january-2025-release-notes&#x22;&#x3E;damien.zone January 2025 Release Notes&#x3C;/h2&#x3E;
&#x3C;h3 id=&#x22;new-favicon--avatar&#x22;&#x3E;new favicon / avatar&#x3C;/h3&#x3E;

&#x3C;img src=&#x22;https://damien.zone/avatar/avatar-border.png&#x22; alt=&#x22;A black cat with a red bandana, holding a baguette and looking to the left&#x22; /&#x3E;

&#x3C;p&#x3E;&#x3C;a href=&#x22;https://www.wavebeem.com/&#x22;&#x3E;Sage&#x3C;/a&#x3E; drew a lovely pixel-art version of my avatar! We spent a lot of time making sure it looks &#x3C;em&#x3E;sharp as hell&#x3C;/em&#x3E; everywhere. The favicon shows up fine in RSS readers as well. I&#x27;ll try to make a post documenting how all of this was done because some of the tricks I used are a little bit silly.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;color-palette-changes&#x22;&#x3E;color palette changes&#x3C;/h3&#x3E;
&#x3C;p&#x3E;I also changed several aspects of the main design regarding contrast and colors. There are too many to list, so enjoy a comparison below:&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/damienzone25/damienzone2025-before-dark.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/damienzone25/damienzone2025-before-dark.webp&#x22; alt=&#x22;Before, in dark mode&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Before, in dark mode&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/damienzone25/damienzone2025-after-dark.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/damienzone25/damienzone2025-after-dark.webp&#x22; alt=&#x22;After, in dark mode&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;After, in dark mode&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/damienzone25/damienzone2025-before-light.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/damienzone25/damienzone2025-before-light.webp&#x22; alt=&#x22;Before, in light mode&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Before, in light mode&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/damienzone25/damienzone2025-after-light.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/damienzone25/damienzone2025-after-light.webp&#x22; alt=&#x22;After, in light mode&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;After, in light mode&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Hopefully, these changes make the site a bit nicer to look at and read. I will continue iterating on it over time because these things are never finished.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;layout--content-changes&#x22;&#x3E;layout / content changes&#x3C;/h3&#x3E;
&#x3C;p&#x3E;The layout is still very much based on the &#x22;Terminal&#x22; theme that Bearblog provides, but I tweaked the layout of a few pages:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;The homepage now has a shorter description, the list of recent posts, and that&#x27;s it.&#x3C;/li&#x3E;
&#x3C;li&#x3E;I might experiment with the homepage a bit more; at some point, I&#x27;d like to retire &#x3C;a href=&#x22;https://erambert.me/&#x22;&#x3E;erambert.me&#x3C;/a&#x3E; in favor of this current site.&#x3C;/li&#x3E;
&#x3C;li&#x3E;The links page has been reorganized and redesigned.&#x3C;/li&#x3E;
&#x3C;li&#x3E;The footer is now minimal, with only links to the &#x3C;a href=&#x22;/links&#x22;&#x3E;links&#x3C;/a&#x3E; and &#x3C;a href=&#x22;/credits&#x22;&#x3E;credits&#x3C;/a&#x3E; pages. The webring widget now lives on the links page.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;h3 id=&#x22;other-changes&#x22;&#x3E;other changes&#x3C;/h3&#x3E;
&#x3C;p&#x3E;The &#x3C;a href=&#x22;/feed.xml&#x22;&#x3E;feed&#x3C;/a&#x3E; is now an Atom feed instead of being either Atom or RSS. The actual feed is available at &#x3C;a href=&#x22;/feed.xml&#x22;&#x3E;/feed.xml&#x3C;/a&#x3E;, but I have redirects set up to ensure that RSS clients querying &#x3C;code&#x3E;/feed&#x3C;/code&#x3E; still receive something. As far as I can tell, RSS readers seem to be fine with a given feed changing format like that... so hopefully nothing breaks? We&#x27;ll see!&#x3C;/p&#x3E;
&#x3C;p&#x3E;The code is/will be available on &#x3C;a href=&#x22;https://github.com/eramdam/damien.zone&#x22;&#x3E;GitHub&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;happy-new-year-everyone&#x22;&#x3E;happy new year, everyone!&#x3C;/h2&#x3E;
&#x3C;p&#x3E;And that&#x27;s it. I hope and wish for 2025 to serve you and all of us well.&#x3C;/p&#x3E;
&#x3C;p&#x3E;See ya,&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/new-year-new-site&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Justice Live! in Paris, 2024 // tiny update</title>
          <link href="https://damien.zone/justice-live-in-paris-2024" rel="alternate"/>
          <id>https://damien.zone/justice-live-in-paris-2024</id>
          <published>2024-12-21T23:00:00Z</published>
          <updated>2024-12-22T09:06:33Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;Saw Justice two times in Paris last week, which makes it four times this year&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;. While my spot for the first Paris show was not great (literally the highest, furthest from the stage), I had a much better spot the night after.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Like in &#x3C;a href=&#x22;https://damien.zone/justice-at-portola-2024/&#x22;&#x3E;September at Portola&#x3C;/a&#x3E;, I managed to get a pretty good spot on the floor, which netted me some pretty good shots, despite not taking nearly as many as I did back then. I also lucked out and managed to get high-fives from both Xavier and Gaspard (I missed both last time lol) so I still feel pretty good about that lmao.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Like last time, all of these are shot on my iPhone 13 Pro using &#x3C;a href=&#x22;https://halide.cam/&#x22;&#x3E;Halide&#x3C;/a&#x3E; in &#x3C;a href=&#x22;https://www.lux.camera/introducing-process-zero-for-iphone/&#x22;&#x3E;&#x22;Process Zero RAW&#x22;&#x3C;/a&#x3E; with only exposure and contrasts being adjusted after the fact.&#x3C;br /&#x3E;
The pictures below are thumbnails, but you can/should click on them to get the full-size JPEGs if you want to pixel peep and taste that sweet-sweet noise &#x1F604;&#x3C;/p&#x3E;
&#x3C;hr /&#x3E;
&#x3C;p&#x3E;Apart from that, I&#x27;m on a Christmas break for the next couple of weeks. I have a bunch of stuff I wanna watch, read and play, I also want to start exploring ways of migrating this blog to &#x3C;a href=&#x22;https://www.11ty.dev/&#x22;&#x3E;Eleventy&#x3C;/a&#x3E; (or something else, who knows).
I don&#x27;t know if I&#x27;ll get to even half of that &#x3C;em&#x3E;but&#x3C;/em&#x3E; it will be nice to spend some time away from work and Online a bit.&#x3C;br /&#x3E;
Oh and also, I renamed this blog to &#x22;damien&#x27;s zone&#x22;. It&#x27;s not super creative, but it feels a bit nicer than having my full legal name in there lmao.&#x3C;/p&#x3E;
&#x3C;p&#x3E;See y&#x27;all in the new year &#x2764;&#xFE0F;,&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_20241218212945.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_INSTA_20241218212945.jpg&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_20241218214206.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_INSTA_20241218214206.jpg&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_20241218215830.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_INSTA_20241218215830.jpg&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_20241218222617.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_INSTA_20241218222617.jpg&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_20241218222629.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_INSTA_20241218222629.jpg&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_20241218223033.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_INSTA_20241218223033.jpg&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_20241218223039.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_INSTA_20241218223039.jpg&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_20241218223450.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damiensfiles.b-cdn.net/justice-paris-2024/DMN_INSTA_20241218223450.jpg&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;Boston, San Francisco, and now Paris. &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/justice-live-in-paris-2024&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Audio in space</title>
          <link href="https://damien.zone/audio-in-space" rel="alternate"/>
          <id>https://damien.zone/audio-in-space</id>
          <published>2024-12-13T06:02:00Z</published>
          <updated>2024-12-13T06:03:01Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;Ever since I first tried it shortly after its introduction, Dolby Atmos on Apple Music felt, to me, gimmicky at best and counterproductive at worst? It&#x27;s like, either the effect is &#x3C;em&#x3E;too&#x3C;/em&#x3E; noticeable and it&#x27;s distracting &#x3C;em&#x3E;or&#x3C;/em&#x3E; it just doesn&#x27;t add anything when it just doesn&#x27;t make a whole song fall flat? If that makes sense?&#x3C;/p&#x3E;
&#x3C;p&#x3E;At any rate, I was having a normal evening and randomly decided to give it a try again, and boy do I have thoughts.&#x3C;/p&#x3E;
&#x3C;p&#x3E;A little setup note: all my listening is being done on Apple Music on macOS 15.1.1, with AirPods Max, with the &#x22;Lossless (ALAC up to 24-bit/48kHz)&#x22; preset, &#x22;Dolby Atmos&#x22; set to &#x22;Always On&#x22; &#x3C;a href=&#x22;/img/blog/442x.webp&#x22;&#x3E;like so&#x3C;/a&#x3E; and &#x22;Spatial Audio&#x22; set to &#x22;Fixed&#x22; in macOS.&#x3C;br /&#x3E;
I also used the &#x3C;a href=&#x22;https://dodoapps.io/music-library-tracker/&#x22;&#x3E;&#x22;Music Library Tracker&#x22;&#x3C;/a&#x3E; app on iOS to even &#x3C;em&#x3E;find&#x3C;/em&#x3E; which tracks in my library were available in Spatial Audio! Truly bonkers that I need a 3rd party app to do that, but whatever.&#x3C;br /&#x3E;
Also, I&#x27;m putting embed codes for each track. I&#x27;m going to assume Dolby Atmos is &#x3C;em&#x3E;not&#x3C;/em&#x3E; available when playing them from the web, but at least it&#x27;ll be easy to open them in a native Apple Music app if you have that.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Anyway, here are my thoughts gathered after listening to a few Spatial Audio tracks from the ~630 available in my library. I will try to gather a relatively broad range of genres, but it&#x27;s my own library, so there will be a clear bias lmao.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;kraftwerk---trans-europa-express--metall-auf-metall--abzug&#x22;&#x3E;&#x3C;a href=&#x22;https://music.apple.com/us/album/trans-europa-express-metall-auf-metall-abzug-live/1572524711?i=1572525066&#x22;&#x3E;Kraftwerk - Trans-Europa Express / Metall Auf Metall / Abzug&#x3C;/a&#x3E;&#x3C;/h2&#x3E;

&#x3C;p&#x3E;I could write a poem about &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Trans-Europe_Express_(album)&#x22;&#x3E;Kraftwerk&#x27;s Trans-Europa Express&#x3C;/a&#x3E;, it is genuinely one of my favorite electronic music albums of all time, I think. And to be clear, I do &#x3C;em&#x3E;not&#x3C;/em&#x3E; mean Trans-&#x3C;em&#x3E;Europe&#x3C;/em&#x3E; Express, Kraftwerk shall be listened to in German or shan&#x27;t be listened to, in my humble opinion.&#x3C;/p&#x3E;
&#x3C;p&#x3E;At any rate, this Spatial Audio... edition? Mastering? Of the 3-track medley is honestly a pretty great example of Spatial Audio when it actually &#x3C;em&#x3E;works&#x3C;/em&#x3E;. The lossless version is already great because this track is a banger among Kraftwerk&#x27;s bangers, but the minimal(ist) production and industrial sound design really works well when &#x22;mapped&#x22; into space. The &#x3C;em&#x3E;Metall Auf Metall&#x3C;/em&#x3E; section (around the 4min mark) is &#x3C;em&#x3E;a trip&#x3C;/em&#x3E; in the best way. It&#x27;s like you &#x3C;em&#x3E;are&#x3C;/em&#x3E; in the Trans-Europa Express, it rules.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Good times, recommend, if Kraftwerk&#x27;s is your jam.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;hikaru-utada---michi&#x22;&#x3E;&#x3C;a href=&#x22;https://music.apple.com/us/album/michi/1428766398?i=1428767651&#x22;&#x3E;Hikaru Utada - Michi&#x3C;/a&#x3E;&#x3C;/h2&#x3E;

&#x3C;p&#x3E;I feel this one is a good example of a great track whose Spatial Audio master falls on its face and ruins it. The drums stand out because they sound, somehow, tinny, it&#x27;s honestly pretty distracting! The vocals sometimes sound a bit &#x22;muffled&#x22; but mostly fine &#x3C;em&#x3E;but&#x3C;/em&#x3E; are completely overpowered by the strings/rest of the backing instrumentals during the chorus. The whole thing ends up sounding like you accidentally turned out a bad EQ preset on the track. A damn shame.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;michael-jackson---thriller&#x22;&#x3E;&#x3C;a href=&#x22;https://music.apple.com/us/album/thriller/273048762?i=273048787&#x22;&#x3E;Michael Jackson - Thriller&#x3C;/a&#x3E;&#x3C;/h2&#x3E;

&#x3C;p&#x3E;I probably don&#x27;t need to introduce this track. It&#x27;s a classic. You know it, I know it, we all know it.&#x3C;br /&#x3E;
The original already feels &#x22;immersive&#x22; due to its cinematic ambiance and impeccable mastering. I think it&#x27;s one of the first tracks I&#x27;ve listened to that &#x22;rewarded me&#x22; for paying attention to things like &#x22;that one tiny guitar playing a few chords in the background of the chorus&#x22;, good stuff.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The Spatial Audio master is...perplexing? Don&#x27;t get me wrong, it&#x27;s well-made! The vibe of the stereo version is intact, the door is creaky, the wolves&#x27; howls are spooky, the groove is &#x3C;em&#x3E;&#x3C;em&#x3E;chef&#x27;s kiss&#x3C;/em&#x3E;&#x3C;/em&#x3E; and Vincent Price&#x27;s evil laugh gives me both the goosebumps and a massive grin on my face. It&#x27;s fucking Thriller!&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;strong&#x3E;But&#x3C;/strong&#x3E;. They fucked with it! I do not know if it was intentional or if someone fucked up, but they messed with it!
From the very intro, it&#x27;s noticeable, the creaky door sounds different, almost as if it had a &#x22;record scratch&#x22; sound effect applied to it? There are a few piano chords added here and there, maybe a few more wolves howling in the background, shit like that.&#x3C;/p&#x3E;
&#x3C;p&#x3E;And it&#x27;s like, yeah, the effect is sold, and you can&#x27;t miss the &#x22;spatialness&#x22; of it but... man it&#x27;s distracting!! Perhaps I&#x27;m just obsessive enough that any tiny change would have &#x27;triggered&#x27; me, but it&#x27;s a bit of a bummer in my opinion because I do not think this Atmos master needed any extra &#x22;fluff&#x22; like that. At least the outro with Vincent Prince is (mostly) unscathed, thank god.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Not a bad time, but given the source material, I&#x27;m peeved.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;kendrick-lamar---gnx&#x22;&#x3E;&#x3C;a href=&#x22;https://music.apple.com/us/album/gnx/1781270319&#x22;&#x3E;Kendrick Lamar - GNX&#x3C;/a&#x3E;&#x3C;/h2&#x3E;

&#x3C;p&#x3E;I&#x27;m cheating and including the whole album because I cannot choose and also because, frankly, GNX is a no-skip-album. The Atmos master is not perfect, but it&#x27;s pretty damn close!&#x3C;/p&#x3E;
&#x3C;p&#x3E;I wanted to write a &#x22;highlights&#x22; section, but I quickly realized I would just say that every track slaps in Spatial Audio because, well, they do in specific ways because GNX is a good album.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Give it a listen if you liked the album.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;green-day---american-idiot&#x22;&#x3E;&#x3C;a href=&#x22;https://music.apple.com/us/album/american-idiot/1161539183?i=1161539471&#x22;&#x3E;Green Day - American Idiot&#x3C;/a&#x3E;&#x3C;/h2&#x3E;

&#x3C;p&#x3E;What a mess, dude. The whole thing sounds so &#x22;small&#x22; and tinny in Spatial Audio compared to the (remastered?) stereo lossless version. Unclear to me if this is just a thing with &#x22;rock&#x22; songs in Atmos or just this particular master but &#x3C;em&#x3E;man&#x3C;/em&#x3E;, what a waste.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Keep to the stereo version on this one.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;justice---hyperdrama&#x22;&#x3E;&#x3C;a href=&#x22;https://music.apple.com/us/album/hyperdrama/1724935208&#x22;&#x3E;Justice - Hyperdrama&#x3C;/a&#x3E;&#x3C;/h2&#x3E;

&#x3C;p&#x3E;Another album, you can&#x27;t stop me! ... And I don&#x27;t know, man, the Spatial Audio just sounds mid on this one? Hyperdrama is a banger of an album, but it 100% sounds better in stereo than in Atmos. It&#x27;s not even a contest.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;bo-burnham---welcome-to-the-internet&#x22;&#x3E;&#x3C;a href=&#x22;https://music.apple.com/us/album/welcome-to-the-internet/1571419211?i=1571419368&#x22;&#x3E;Bo Burnham - Welcome to The Internet&#x3C;/a&#x3E;&#x3C;/h2&#x3E;

&#x3C;p&#x3E;Remember this song? Anyway, I wanted to end on a good note because I think here the Spatial Audio works here! I wonder if the mastering work from the Netflix special (who, I assume, had surround sound?) was used as a base here? Either way, it&#x27;s great here.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;conclusion-spatial-audio-is-still-sort-of-a-mixed-bag&#x22;&#x3E;Conclusion: Spatial Audio is still sort of a mixed bag*&#x3C;/h2&#x3E;
&#x3C;p&#x3E;* In my experience.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I would be tempted to say that Spatial Audio only really works on specific genres or very specific types of tracks/records, but even in the same genre... the results vary wildly?&#x3C;br /&#x3E;
Perhaps Spatial Audio only works when the master is treated as its own thing and just not a checkbox on a to-do list.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I don&#x27;t know, I&#x27;m not an audio engineer, just a guy who listens to music perhaps a bit too much and who has opinions.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Thank you for coming to my TED talk,&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x200B;&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/audio-in-space&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Cool Selection of Stuff: early December 2024</title>
          <link href="https://damien.zone/cool-selection-of-stuff-early-december-2024" rel="alternate"/>
          <id>https://damien.zone/cool-selection-of-stuff-early-december-2024</id>
          <published>2024-12-07T23:20:11Z</published>
          <updated>2024-12-07T23:20:11Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;Last month definitely has been something, huh? Globally and also personally because, &#x3C;em&#x3E;man&#x3C;/em&#x3E;, time has been &#x3C;em&#x3E;flying&#x3C;/em&#x3E; these past few weeks. What started as a small list of links at the beginning of November morphed into whatever will happen in this post, welp!&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;playing&#x22;&#x3E;playing&#x3C;/h3&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;&#x3C;a href=&#x22;https://store.steampowered.com/app/3146520/WEBFISHING/&#x22;&#x3E;Webfishing&#x3C;/a&#x3E;!! What a lovely little game.&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;a href=&#x22;https://50games.fun/&#x22;&#x3E;UFO 50&#x3C;/a&#x3E;, which has been made &#x3C;em&#x3E;so&#x3C;/em&#x3E; much more enjoyable by my recent purchase of an &#x3C;a href=&#x22;https://www.8bitdo.com/pro2/&#x22;&#x3E;8bitdo Pro 2 controller&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;a href=&#x22;https://store.steampowered.com/app/2702490/TETRACHROMA/&#x22;&#x3E;Tetrachroma&#x3C;/a&#x3E;.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;I think I want to use my upcoming Christmas break to play more video games, especially ones I&#x27;ve had on my &#x22;backlog&#x22; for a hot minute &#x1F624;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;listening&#x22;&#x3E;listening&#x3C;/h3&#x3E;
&#x3C;p&#x3E;November was great for music, at least!&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;The new &#x3C;a href=&#x22;https://my-gnx.com/&#x22;&#x3E;Kendrick Lamar album&#x3C;/a&#x3E; has been on heavy rotation for me. I need to dig into more West Coast rap...&#x3C;/li&#x3E;
&#x3C;li&#x3E;I finally found what the fuss was all about and checked out &#x3C;a href=&#x22;https://magdalenabay.bandcamp.com/album/mercurial-world&#x22;&#x3E;Mercurial World&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://magdalenabay.bandcamp.com/album/imaginal-disk&#x22;&#x3E;Imaginal Disk&#x3C;/a&#x3E; by Magdalena Bay and, man, music rules, y&#x27;all.&#x3C;/li&#x3E;
&#x3C;li&#x3E;The year is 2024, and I only now found out about Together&#x27;s (Thomas Bangalter and DJ Falcon) version of &#x22;Call On Me&#x22; and watched &#x3C;a href=&#x22;https://www.youtube.com/watch?v=wyYAiU4DKUY&#x22;&#x3E;this excellent documentary&#x3C;/a&#x3E; about the whole situation about this track.&#x3C;/li&#x3E;
&#x3C;li&#x3E;I also listened to a lot of &#x3C;a href=&#x22;https://etjusticepourtous.bandcamp.com/album/hyperdrama&#x22;&#x3E;Justice&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://gesaffelstein.lnk.to/GAMMA&#x22;&#x3E;Gesaffelstein&#x3C;/a&#x3E; because they both released banger albums this year, so I&#x27;m allowed to be normal about both. It will happen again.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;And now, the links.&#x3C;/p&#x3E;
&#x3C;hr /&#x3E;
&#x3C;h2 id=&#x22;politics-oof&#x22;&#x3E;politics (oof)&#x3C;/h2&#x3E;
&#x3C;h3 id=&#x22;consolations-of-the-damned-and-its-the-end-of-the-world-as-we-know-it&#x22;&#x3E;&#x3C;a href=&#x22;https://aevangeline.substack.com/p/consolations-of-the-damned&#x22;&#x3E;Consolations of the Damned&#x3C;/a&#x3E;, and &#x3C;a href=&#x22;https://offb.substack.com/p/its-the-end-of-the-world-as-we-know&#x22;&#x3E;It&#x27;s the End of the World As We Know It.&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;It&#x27;s one of the triumphantly insipid parts of humanity - that some of us never can quite give up, even when all signs point to our personal immiseration. For some fool reason, even when sinking into mire, some humans try to plant seeds.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;For many white left-libs and rad-libs across the USA, it was the end of the world as they knew it. For me, someone who hasn&#x2019;t stopped seeing the face of every martyr I held in my arms &#x2018;til they died in Gaza, it was another fucking Wednesday.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;These two posts have been resonating in my head for a minute, I think you could see them as polar opposites, but I feel they&#x27;re two sides of the same coin?&#x3C;/p&#x3E;
&#x3C;p&#x3E;I think it&#x27;s fair to say that: shit sucks, shit &#x3C;em&#x3E;will&#x3C;/em&#x3E; suck, but hope is necessary. I know I&#x27;ll try to keep this in mind for the next few years as I try to do whatever I can at my own level.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;the-pervocracy-resistance-is-not-an-emotion&#x22;&#x3E;The Pervocracy: &#x3C;a href=&#x22;https://pervocracy.com/essays/resistance-is-not-an-emotion/&#x22;&#x3E;Resistance is not an emotion&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;Bottom line was, I &#x3C;em&#x3E;cared&#x3C;/em&#x3E; about the things happening in this country. And the angrier I got, the more the anger itself felt like caring. They say &#x201C;if you&#x2019;re not outraged, you&#x2019;re not paying attention,&#x201D; right? Well, I sure was paying attention! I was paying so much attention I couldn&#x2019;t sleep and I couldn&#x2019;t enjoy anything!&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;&#x3C;em&#x3E;Yup&#x3C;/em&#x3E;, felt that one. The first set of Trump years were maddening as an immigrant who had (at this point) &#x22;just arrived&#x22; in the U.S., it was very easy to fall into the &#x22;god I need to at least pay attention because who knows what that bozo will do/say&#x22; trap and drive myself insane over things I had no control over.&#x3C;br /&#x3E;
Not doing that again!&#x3C;br /&#x3E;
I&#x27;m still pissed, and I doubt I&#x27;ll be less so anytime soon, but it feels healthier to try to channel that into actions that actually help people around me. Like Natalie said: &#x3C;a href=&#x22;https://nex-3.com/blog/the-thing-about-making-the/&#x22;&#x3E;&#x22;There&#x27;s so much that needs doing, and even if you just do a bit of it you&#x27;re helping.&#x22;&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;that-nerd-shit&#x22;&#x3E;that nerd shit&#x3C;/h2&#x3E;
&#x3C;h3 id=&#x22;cathode-ray-dude-linux-on-the-steamdeck-lol&#x22;&#x3E;cathode ray dude: &#x3C;a href=&#x22;https://blog.cathoderaydude.com/doku.php?id=blog:linux_on_the_steamdeck_lol&#x22;&#x3E;linux on the steamdeck lol&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;one of the great things about humans is our ability to communicate, to share experiences so that we don&#x27;t all have to learn things &#x201C;the hard way.&#x201D; why people online, particularly linux people, are so quick to discard that basic tenet of our existence is beyond me. all you have to do is say &#x201C;yep, it works,&#x201D; without the &#x201C;obviously&#x201D; at the end - or just say nothing at all. that one&#x27;s incredibly easy. possibly the easiest choice&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;The Steam Deck part of this post isn&#x27;t really what I&#x27;m interested in, hehe.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;ben-mini-img_0416&#x22;&#x3E;ben-mini: &#x3C;a href=&#x22;https://ben-mini.github.io/2024/img-0416&#x22;&#x3E;IMG_0416&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;That the iPhone had a &#x22;Send to YouTube&#x22; feature is one of these things that I knew about because I remember it being announced at the time, but reading this article felt like digging a core memory, in a good way.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;ai-3-there-is-no-road-from-here-to-there&#x22;&#x3E;&#x3C;a href=&#x22;https://discourse.suttacentral.net/t/ai-3-there-is-no-road-from-here-to-there/33426&#x22;&#x3E;AI-3: There is no road from here to there&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;AI is doing the same thing, except we are bewitched by a simulacrum. Human attention worldwide has been transfixed, our thoughts and fears and hopes and fantasies magnetized by the appearance of something so alien that seems somehow like us. We want it to be real. We want to be it. In doing so we long for the erasure of our own subjectivity.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;It won&#x27;t surprise you to learn that I never really believed in the &#x22;we will be able to make a superintelligence&#x22; claims from the AI industry, but this post tackling the question by using Buddhist texts as framing is fascinating.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;tom-macwright-on-not-using-copilot&#x22;&#x3E;Tom MacWright: &#x3C;a href=&#x22;https://macwright.com/2024/11/20/not-using-copilot.html&#x22;&#x3E;On not using copilot&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;LLM assistants are chat interfaces. You beg the computer to do something, it does something wrong, you ask it to fix the problem. You&#x2019;re managing. You&#x2019;re acting as a manager, and chatting.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Sometimes that&#x2019;s a useful arrangement. Heck, &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/ELIZA&#x22;&#x3E;ELIZA&#x3C;/a&#x3E; was occasionally useful even though it was a tiny, scripted experience. Talk therapy can be good, and chat interfaces can be productive. But at least for some of us, the need to keep asking for something, trying to define the outputs we want and clarify and re-clarify: this is managing, and sometimes it&#x2019;s nicer to write in solitude than to beg the computer like an micromanager.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;Big same.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;mathew-duggan-self-hosting-isnt-a-solution-its-a-patch&#x22;&#x3E;Mathew Duggan: &#x3C;a href=&#x22;https://matduggan.com/self-hosting-isnt-a-solution-its-a-patch/&#x22;&#x3E;Self-Hosting Isn&#x27;t a Solution; It&#x27;s A Patch&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;What people actually need are laws. Regulations like the GDPR must become the international standard for platforms handling personal data. These laws ensure a basic level of privacy and data rights, independent of whether a judge forces a bored billionaire to buy your favorite social network. Suggesting self-hosting as a solution in the absence of such legal protections is as naive as believing encrypted messaging platforms alone can protect you from government or employer overreach.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;I self-host probably more than the average person, and I&#x27;m thinking about ways to self-host/control more stuff in the future but this article raises a lot of good points.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;arnoorg-on-the-origins-of-ds_store&#x22;&#x3E;arno.org: &#x3C;a href=&#x22;https://www.arno.org/on-the-origins-of-ds-store&#x22;&#x3E;On the origins of DS_store&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Finishing this section with some extra nerd trivia.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;miscellanea&#x22;&#x3E;miscellanea&#x3C;/h2&#x3E;
&#x3C;h3 id=&#x22;nat-clayton-someplace-elsewhere-almost-every-cat-i-met-this-year&#x22;&#x3E;Nat Clayton (someplace elsewhere): &#x3C;a href=&#x22;https://blog.someplace-else.xyz/almost-every-cat/&#x22;&#x3E;(Almost) Every Cat I Met This Year&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Cats are good as hell.&#x3C;/p&#x3E;
&#x3C;hr /&#x3E;
&#x3C;p&#x3E;That&#x27;s what I have for you this time. I also recently rambled about &#x3C;a href=&#x22;https://damien.zone/thoughts-about-mastodon-and-the-new-twitter/&#x22;&#x3E;Websites&#x2122;&#xFE0F;&#x3C;/a&#x3E;, maybe it might be interesting to you? Who knows.&#x3C;/p&#x3E;
&#x3C;p&#x3E;See you in the next one!&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/cool-selection-of-stuff-early-december-2024&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Thoughts about Mastodon and the &#x22;new Twitter&#x22;</title>
          <link href="https://damien.zone/thoughts-about-mastodon-and-the-new-twitter" rel="alternate"/>
          <id>https://damien.zone/thoughts-about-mastodon-and-the-new-twitter</id>
          <published>2024-11-23T22:14:48Z</published>
          <updated>2024-11-23T22:14:48Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;I keep telling myself I should stop thinking about social media so much, especially in the &#x22;current moment&#x22;, but it keeps happening. This post started as a bunch of posts on Mastodon until I stopped myself and decided to Blog About It instead.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;mastodon-is-fine&#x22;&#x3E;Mastodon is fine&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Eugen being the &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Benevolent_dictator_for_life&#x22;&#x3E;BDFL&#x3C;/a&#x3E; of Mastodon (the project) might have been beneficial in the early days, but it feels more and more like a liability at this point.&#x3C;br /&#x3E;
If Mastodon is to survive for another 8 years, it cannot be run as a &#x3C;a href=&#x22;https://wxcafe.net/posts/when_a_toy_isnt_a_toy_anymore/&#x22;&#x3E;pet project&#x3C;/a&#x3E; anymore. And it also should not be run as &#x22;just&#x22; a Twitter-like anymore because Bluesky is effectively winning that battle with more resources than the Mastodon project could ever get.&#x3C;/p&#x3E;
&#x3C;p&#x3E;A lot of the good ideas for the Fediverse aren&#x27;t coming from Eugen or Mastodon at this point, and they rarely involve just &#x22;being another Twitter&#x22;. Which leads me to my next point.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;who-is-the-new-twitter-is-a-boring-question&#x22;&#x3E;&#x22;Who is the new Twitter?&#x22; is a boring question&#x3C;/h3&#x3E;
&#x3C;p&#x3E;I really do not like this question.&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;
This isn&#x27;t me being salty about Bluesky &#x22;winning&#x22;, by the way. I would be bothered the same if Mastodon was being declared a &#x22;winner&#x22; because:&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;strong&#x3E;Why should we have only one website, exactly?&#x3C;/strong&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Why is this all we care about? Why is this the focus? Why do we obsess over who has the most (active) users?&#x3C;/p&#x3E;
&#x3C;p&#x3E;Are we constantly arguing about decentralization, who does it and who doesn&#x27;t, and complaining about monopolies only to want (effectively) a monopoly for our online spaces? Really?&#x3C;/p&#x3E;
&#x3C;p&#x3E;Sure, it&#x27;s more annoying, but I think it&#x27;s healthier to have different spaces for different people.&#x3C;br /&#x3E;
I&#x27;ve been on Twitter since 2009, Mastodon since 2017, and Bluesky since early 2023 and at this point, I can say that all of these are true:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;I know people who only feel comfortable being on Mastodon and not Bluesky, &#x3C;em&#x3E;and vice versa&#x3C;/em&#x3E;.&#x3C;/li&#x3E;
&#x3C;li&#x3E;I know people for whom Twitter is still Their Only Place. This list gets smaller by the day and is only really there because Bluesky doesn&#x27;t have locked accounts (yet), but it exists.&#x3C;/li&#x3E;
&#x3C;li&#x3E;...and I know people who have withdrawn from social media altogether because the remaining options just feel terrible to them.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;This is the kind of thing I think about when I see people bicker about who is &#x22;winning the Twitter-like war&#x22;. I really don&#x27;t care about who is winning because I do not believe it is a conflict worth thinking about.&#x3C;/p&#x3E;
&#x3C;p&#x3E;See ya,&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;I also roll my eyes at the fact that, most of the time, those asking it treat Mastodon as if it only &#x22;became a thing&#x22; in November 2022. It has been around for &#x3C;em&#x3E;eight years&#x3C;/em&#x3E; at this point! A lot of social media websites don&#x27;t even last half as long! But most people didn&#x27;t care until Elon Musk bought Twitter and &#x22;made it bad&#x22; (as if it were perfect before). But whatever, I&#x27;m annoyed about it, but it&#x27;s just because I&#x27;m clearly not neurotypical enough to hear someone getting details/a story wrong and moving on as if it didn&#x27;t happen. &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/thoughts-about-mastodon-and-the-new-twitter&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>buttons</title>
          <link href="https://damien.zone/buttons" rel="alternate"/>
          <id>https://damien.zone/buttons</id>
          <published>2024-11-05T03:46:00Z</published>
          <updated>2024-11-05T03:48:40Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;You know, it always surprises me in the best way possible to see my &#x3C;a href=&#x22;https://damien.zone/links/&#x22;&#x3E;website&#x27;s button&#x3C;/a&#x3E; on other people&#x27;s websites. I have literally no way of knowing who does it otherwise (because the file is hosted by GitHub so I don&#x27;t have analytics, and I&#x27;m sure some folks re-host it themselves) so every time it happens it&#x27;s a surprise. It&#x27;s great.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Always appreciate it &#x26;lt;3&#x3C;/p&#x3E;
&#x3C;p&#x3E;- damien&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/buttons&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Cool Selection of Stuff: end of October 2024</title>
          <link href="https://damien.zone/cool-selection-of-stuff-end-of-october-2024" rel="alternate"/>
          <id>https://damien.zone/cool-selection-of-stuff-end-of-october-2024</id>
          <published>2024-11-03T07:00:00Z</published>
          <updated>2024-11-05T03:38:19Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;Programming note: remember link roundups? Well, I&#x27;m deciding to call them by a different name now. Why? So I can make a silly pun.
I wanted to go with &#x22;Cool Stuff Sunday&#x22; at first, but I&#x27;m not fooling myself in thinking I&#x27;ll stick to posting these on Sundays.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Let&#x27;s get to it, there&#x27;s a lot of stuff to talk about.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;social-media-meta&#x22;&#x3E;Social Media meta&#x3C;/h2&#x3E;
&#x3C;p&#x3E;For better or worse, I still think probably far too much about social media, so I can&#x27;t help but be into articles about it.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;tom-date-em-ups-i-want-you-to-dream&#x22;&#x3E;Tom (Date &#x27;em Ups): &#x3C;a href=&#x22;https://dateemups.com/cohost-finale/&#x22;&#x3E;I want you to dream&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;You can have dreams, Cohost. And when you&#x27;re finally done making one come true, you can go on and have more. Dreams are why I&#x27;m here, why I&#x27;ve survived, and I want you, all of you to have them, too, more than anything else. Wherever the winds take us all after this, I hope you hold onto those dreams. Don&#x27;t let go of them for anything. Anything. No matter how crushing the world gets, no matter how tall the barriers to entry are, nothing whatsoever. I had to hold onto mine tightly for over two whole decades, but damn it, I willed it into reality and I&#x27;m going to keep doing the exact same thing with what&#x27;s in my sights now or die trying.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;Another cohost-related post, it will happen again, I&#x27;m not sorry.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;luna-online-following-and-starter-packs&#x22;&#x3E;Luna: &#x3C;a href=&#x22;https://moonbase.lgbt/blog/online-following-starter-packs/&#x22;&#x3E;Online following and Starter Packs&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;I want people to follow me naturally because they enjoy my posts in particular, I don&#x2019;t want a tech/demoscene/gamedev/etc audience showing up in bulk just because someone else decided to put me on a list without my prior consent.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;It is not a secret that I am not exactly fond of Bluesky. I use it, but I &#x3C;em&#x3E;tolerate&#x3C;/em&#x3E; it. Bluesky&#x27;s &#x22;starter packs&#x22;, much like Twitter&#x27;s &#x22;Follow all&#x22;&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E; feature, are... misguided? I see where they&#x27;re coming from, it&#x27;s hard to &#x22;build a feed&#x22; when you start on a Twitter-like website but, like Luna here, I can&#x27;t help but feel this will produce Some Weird Results.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I think following a starter pack is doing yourself a disservice because you&#x27;re just injecting people into your feed without getting a feel of what their posts are like, and people who are added to them have little way of doing much about it.
You can &#x22;just block the creator of a pack&#x22; but this isn&#x27;t a great solution. Some people might prefer to never be put in the spotlight &#x3C;em&#x3E;at all&#x3C;/em&#x3E;, sometime it might be awkward for people to block a starter pack&#x27;s creator. The fact there isn&#x27;t an &#x22;opt me out&#x22; button is &#x3C;em&#x3E;bonkers&#x3C;/em&#x3E; to me, but ultimately doesn&#x27;t surprise me coming from Bluesky. But I&#x27;m just a hater, so what do I know.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Build your feed slowly but surely, mute and unfollow liberally, avoid accounts that are just glorified RSS feeds. It&#x27;s not perfect, but I know I would &#x3C;em&#x3E;explode&#x3C;/em&#x3E; if I followed dozens of new people at once, so that&#x27;s what I do.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;websites-meta&#x22;&#x3E;Websites meta&#x3C;/h3&#x3E;
&#x3C;h3 id=&#x22;margot-a-journal-your-website-doesnt-actually-have-to-have-everything&#x22;&#x3E;Margot (a journal): &#x3C;a href=&#x22;https://emaytch.neocities.org/journal#20241024&#x22;&#x3E;&#x22;your website doesn&#x27;t actually have to have everything&#x22;&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;(Sorry, Margot, but I felt the date wasn&#x27;t a good title, hope you forgive me)&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;You don&#x27;t have to recreate everything on the web, or even your favorite social media site! I recommend starting small, working on what you can or what you know, and plan to do more whenever you feel like you have the capacity to do so.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;This is something I have to keep telling myself. The reason I never posted on my blog when it was at &#x3C;code&#x3E;erambert.me/blog&#x3C;/code&#x3E; was that I had built a stack&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-3&#x22; id=&#x22;user-content-fnref-3&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;2&#x3C;/a&#x3E;&#x3C;/sup&#x3E; that was just too distracting to me. I would end up just tinkering and adding yet-another-feature instead of just posting.&#x3C;br /&#x3E;
I am starting to think about &#x3C;em&#x3E;maybe&#x3C;/em&#x3E; migrating to something else in the coming months, but I&#x27;ve enjoyed Bearblog for its &#x22;limitations&#x22; that stop me in my tinker-instead-of-writing tracks. It&#x27;s always a work in progress, and that&#x27;s ok.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;ian-having-a-website-used-to-be-fun&#x22;&#x3E;Ian: &#x3C;a href=&#x22;https://ianspence.com/blog/2024-10/websites-used-to-be-fun/&#x22;&#x3E;Having a Website Used to Be Fun&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;Kill the cop in your head that tells you to share the concerns that Google has. You&#x27;re not Google. Websites should be fun. Enterprise tools like Cloudflare and managed containers aren&#x27;t.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;I felt Ian&#x27;s post in my bones because, like I said above, I painted myself into a similar corner. &#x3C;em&#x3E;Multiple times&#x3C;/em&#x3E; in my past. You, dear reader, know about damien.zone and erambert.me, but my past is full of the corpses of dead blogs. Hopefully, this one won&#x27;t join the graveyard anytime soon.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;pyeri-robotstxt-pitfalls-what-i-learned-the-hard-way&#x22;&#x3E;pyeri: &#x3C;a href=&#x22;https://lobste.rs/s/s6zfxg/robots_txt_pitfalls_what_i_learned_hard&#x22;&#x3E;Robots.txt pitfalls: what I learned the hard way&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;Note: &#x3C;code&#x3E;robots.txt&#x3C;/code&#x3E; is &#x3C;a href=&#x22;https://mastodon.social/@ecn/113397664191346898&#x22;&#x3E;merely a suggestion&#x3C;/a&#x3E; these days, do not treat it as a silver bullet against scrapers and various bots.&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Interesting post about, IMO, easy mistakes to make with the &#x3C;code&#x3E;robots.txt&#x3C;/code&#x3E; syntax.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;general-tech-stuff&#x22;&#x3E;General tech stuff&#x3C;/h2&#x3E;
&#x3C;h3 id=&#x22;louie-mantia-nothing-left-to-solve&#x22;&#x3E;Louie Mantia: &#x3C;a href=&#x22;https://lmnt.me/blog/nothing-left-to-solve.html&#x22;&#x3E;Nothing Left to Solve&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;At some point, we solidified the layout of a calculator. If we change it too much, we diminish value rather than add to it. It might be time to recognize that we have solved some software problems, and the reason why all this stuff gets redesigned repeatedly is simply because companies don&#x2019;t know what to do if these things have been solved already.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;Louie is specifically talking about &#x3C;a href=&#x22;https://www.theverge.com/2024/10/24/24279020/browser-company-ai-browser-arc&#x22;&#x3E;The Browser Company&#x3C;/a&#x3E; building &#x3C;em&#x3E;another&#x3C;/em&#x3E; browser that isn&#x27;t Arc, but his article could apply to so many things in tech at this point.
Maybe this isn&#x27;t the first time it happened, but it really feels like the tech industry is eating its own tail trying to find the Next Big Thing. Welp.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;jason-velazquez-any-technology-indistinguishable-from-magic-is-hiding-something&#x22;&#x3E;Jason Velazquez: &#x3C;a href=&#x22;https://www.fromjason.xyz/p/notebook/any-technology-indistinguishable-from-magic-is-hiding-something/&#x22;&#x3E;Any Technology Indistinguishable From Magic is Hiding Something&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;Listen, I know we want to believe that things are changing for the better. For the first time in a long while, there&#x2019;s hope for the future of the web. There&#x2019;s something in the air, something that feels like meaningful change. Things are happening. It&#x2019;s lovely, actually.&#x3C;br /&#x3E;
[...]&#x3C;br /&#x3E;
And if you&#x2019;re on Mastodon or some other decentralized social media, that&#x2019;s great! Don&#x2019;t be a dick about it. For some people, TikTok is their livelihood. For others, Instagram is the difference between speaking to someone that day or not. We&#x2019;re all just doing the best we can. But we&#x2019;re fighting each other when we could be working together to take these motherfuckers down a peg.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;A good essay about the threat of the ever-growing corporate control of the Web at large and what can be done to (hopefully) fix it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;H/t to &#x3C;a href=&#x22;https://ewie.online/posts/20241012-some-links-you-might/#from-jason-any-technology-indistinguishable-from-magic-is-hiding-something&#x22;&#x3E;Ewie&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://blog.dante.cool/link-roundup-11-the-middle-aged-web/#jason-velazquez-a-hrefhttpswwwfromjasonxyzpnotebookany-technology-indistinguishable-from-magic-is-hiding-somethingany-technology-indistinguishable-from-magic-is-hiding-somethinga&#x22;&#x3E;Dante&#x3C;/a&#x3E; for this one.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;cathode-ray-dude-why-am-i-interested-in-flip-phones&#x22;&#x3E;cathode ray dude: &#x3C;a href=&#x22;https://blog.cathoderaydude.com/doku.php?id=blog:why_am_i_interested_in_flip_phones&#x22;&#x3E;why am i interested in flip phones&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Cathode Ray Dude has a &#x3C;a href=&#x22;https://blog.cathoderaydude.com/doku.php?id=start&#x22;&#x3E;blog&#x3C;/a&#x3E; now! I&#x27;ve been a fan of his &#x3C;a href=&#x22;https://www.youtube.com/@CathodeRayDude&#x22;&#x3E;YouTube channel&#x3C;/a&#x3E; for a while, and I always enjoyed his posting on cohost.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Anyway, this is a good article about flip phones, go read it.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;asthasr-generative-ai-and-the-programmer&#x22;&#x3E;asthasr: &#x3C;a href=&#x22;https://asthasr.github.io/posts/generative-ai/&#x22;&#x3E;Generative AI and the Programmer&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;In other words, as LLMs become more prominent and produce larger proportions of available technical content, the ability of new programmers to bootstrap themselves into competence diminishes because they lack the context necessary to judge the content that they are reading. In effect, only content that is free of LLM influence is suitable for beginner use.&#x3C;/p&#x3E;
&#x3C;p&#x3E;How many aspiring programmers will possess the caution and insight necessary to realize that, and the humility required to accept that older resources might be preferable?&#x3C;/p&#x3E;
&#x3C;p&#x3E;The answer to that question will determine the fate of the industry.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;I am more bullish than the author &#x3C;em&#x3E;against&#x3C;/em&#x3E; LLM-based tools when used in programming tasks. Every time I tried them, they were genuinely distracting and fell on their face when asked to perform more complex tasks that would have been helpful. But this is a good post about the limits of these tools and how, if not used critically, they can be detrimental.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I&#x27;m of the opinion that a programmer is better off learning how to like, make automations and snippets and learn their coding environment by heart rather than using a mediocre plagiarism machine, but that&#x27;s my opinion.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;music-stuff&#x22;&#x3E;Music stuff&#x3C;/h2&#x3E;
&#x3C;h3 id=&#x22;echosoul-new-post&#x22;&#x3E;echosoul: &#x3C;a href=&#x22;https://echosoul.bearblog.dev/new-post/&#x22;&#x3E;New post&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;our scenes will be better off if we support each other openly. sharing the names of the artists and tracks you are playing as a dj is a simple important step.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;I&#x27;m not a DJ but as a listener I can say that, DJ sets are such a useful discovery tool that it&#x27;s saddening to see the practice of hiding your &#x22;sources&#x22; taking place. Besides, there will always be some sicko out there to figure out and post the track lists on dedicated websites, so what&#x27;s the point?&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;morning-music-soichi-terada---sounds-from-the-far-east&#x22;&#x3E;Morning Music: &#x3C;a href=&#x22;https://morningmusic.bearblog.dev/soichi-terada-sounds-from-the-far-east/&#x22;&#x3E;Soichi Terada - Sounds from the Far East&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Great musical recommendation from Misty on her (excellent) Morning Music blog. Love me some house music.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;lynnedrum-normal-for-girls-vii-remixed---postmortem&#x22;&#x3E;lynnedrum: &#x3C;a href=&#x22;https://lynnedrum.bearblog.dev/nfgvii-postmortem/&#x22;&#x3E;NORMAL FOR GIRLS VII: REMIXED - postmortem&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Normal for Girls is one of my favorite music events of the past few years. It&#x27;s always a blast to virtually attend with my friend group in VR, and this edition was no exception. All the sets are great in their own way. Do check it out.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;rebecca-black-boiler-room-dc&#x22;&#x3E;Rebecca Black: &#x3C;a href=&#x22;https://www.youtube.com/watch?v=vkcyXB08BBE&#x22;&#x3E;Boiler Room: DC&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Not a post, but just a DJ set that surprised me. I only recently learned that A) Rebecca Black is still around and that B) she&#x27;s fucking killing it. This set of hers is great and even funny at times. Highly recommend it.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;other-things&#x22;&#x3E;Other things&#x3C;/h2&#x3E;
&#x3C;h3 id=&#x22;nat-clayton-someplace-elsewhere-drifting-through-the-empire-state-in-pictures&#x22;&#x3E;Nat Clayton (Someplace Elsewhere): &#x3C;a href=&#x22;https://blog.someplace-else.xyz/photo-mode-ii/&#x22;&#x3E;Drifting through the Empire State, in pictures&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;But that&#x27;s the process, and it&#x27;s a tremendously enjoyable process at that. It&#x27;s been fun to get out of Edinburgh and try new things, to sneak out a few pics whenever the moment presented itself. I&#x27;m taking things as seriously as I need to right now - there&#x27;s no pressure to post or monetize, this is just for me.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;Nat&#x27;s post resonated a lot with me because, boy, I haven&#x27;t taken pictures with my &#x22;big camera&#x22; in such a long time that the next time I do will absolutely feel like learning everything again. I should get back into it.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;louie-mantia-the-most-famous-queen-song&#x22;&#x3E;Louie Mantia: &#x3C;a href=&#x22;https://lmnt.me/blog/the-most-famous-queen-song.html&#x22;&#x3E;The Most Famous Queen Song&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;Wondering how this possibly could be, I remembered we are from two very different parts of the world.
[...]&#x3C;br /&#x3E;
Some things are not as universal as you&#x2019;d think.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;The same blog, twice in a link roundup? It&#x27;s more likely than you think!&#x3C;br /&#x3E;
Louie&#x27;s post hit close to home because I feel like I have a similar experience dozens of times ever since moving to the U.S. And you could argue that France and the U.S. are much closer to each than Japan and the U.S. are!&#x3C;br /&#x3E;
The world is both very small and very big, I just think it&#x27;s neat.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;priscilla-ghoulnoise-two-big-reasons-cats-follow-you-everywhere&#x22;&#x3E;Priscilla (ghoulnoise): &#x3C;a href=&#x22;https://ghoulnoise.com/two-big-reasons-cats-follow-you-everywhere/&#x22;&#x3E;Two BIG Reasons Cats Follow You Everywhere&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;I had to share this extremely important post.&#x3C;/p&#x3E;
&#x3C;hr /&#x3E;
&#x3C;p&#x3E;That&#x27;s all, folks.&#x3C;/p&#x3E;
&#x3C;p&#x3E;See ya in the next one,&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;I cannot, for the life of me, find any coverage about this feature. But it exists and will show up if you follow someone with, I think, &#x22;a lot&#x22; of followers? It&#x27;s basically a modal that shows a bunch of accounts&#x27; avatars and will prompt you to follow all of them. &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-3&#x22;&#x3E;
&#x3C;p&#x3E;The stack itself isn&#x27;t relevant, IMO. But if you have to know, it&#x27;s using &#x3C;a href=&#x22;https://astro.build&#x22;&#x3E;Astro&#x3C;/a&#x3E;, which I like! I just don&#x27;t think I can trust myself (yet) to use it for a blog again, lol &#x3C;a href=&#x22;#user-content-fnref-3&#x22; data-footnote-backref aria-label=&#x22;Back to reference 2&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/cool-selection-of-stuff-end-of-october-2024&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>End of October 2024 update</title>
          <link href="https://damien.zone/end-of-october-2024-update" rel="alternate"/>
          <id>https://damien.zone/end-of-october-2024-update</id>
          <published>2024-10-28T04:40:00Z</published>
          <updated>2024-10-29T00:55:41Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;Hello, little blog, it&#x27;s been a while! The past two weeks have been uncharacteristically busy for me so, huh, I didn&#x27;t write much here, oops!&#x3C;/p&#x3E;
&#x3C;p&#x3E;I spent a week of vacation in Reno for definitely &#x3C;a href=&#x22;https://goblfc.org/&#x22;&#x3E;normal reasons&#x3C;/a&#x3E;. Turns out, being mostly offline with your friends and other freaks (complimentary) for a whole week is good??? Someone should look into this.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Then, as soon as I came back, my friend &#x3C;a href=&#x22;https://www.joannablackhart.com/&#x22;&#x3E;Joanna&#x3C;/a&#x3E; was in town to visit the &#x3C;a href=&#x22;https://archive.org/&#x22;&#x3E;Internet Archive&#x3C;/a&#x3E;, so I tagged along. I saw a bunch of very cool shit. Like, look at all this stuff!! Tell me this isn&#x27;t cool as hell!!
Excuse the shoddy photography job lmao.&#x3C;/p&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;
&#x3C;img src=&#x22;https://damien.zone/img/blog/servers.webp&#x22; alt=&#x22;three, multiple meters-all servers, all belonging to the Internet Archive&#x22; /&#x3E;
&#x3C;figcaption&#x3E;Servers!! A few of the many (I was told) servers that the Internet Archive HQ in San Francisco houses&#x3C;/figcaption&#x3E;
&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;
&#x3C;img src=&#x22;https://damien.zone/img/blog/petabox.webp&#x22; alt=&#x22;A red-colored, older looking, computer server. The first &#x27;one petabyte box&#x27;.&#x22; /&#x3E;
&#x3C;figcaption&#x3E;A &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/PetaBox&#x22;&#x3E;Petabox&#x3C;/a&#x3E;!! I didn&#x27;t know the Internet Archive had one of these so early (2004!) but it makes sense that they would, after all.&#x3C;/figcaption&#x3E;
&#x3C;/figure&#x3E;
&#x3C;figure data-type=&#x22;image&#x22;&#x3E;
&#x3C;img src=&#x22;https://damien.zone/img/blog/16mm-scanner.webp&#x22; alt=&#x22;A 16mm film scanner. It&#x27;s almost a meter tall and has one big reel on each of its sides&#x22; /&#x3E;
&#x3C;figcaption&#x3E;
A 16mm film scanner! It was super impressive to see move in person, especially considering how &#x22;tiny&#x22; 16mm film is in comparison. 
&#x3C;/figcaption&#x3E;
&#x3C;/figure&#x3E;
&#x3C;p&#x3E;I had other pictures, but they were all of Just Old Stuff. This is also just Old Stuff, but at least it&#x27;s Devices! I&#x27;m never beating the nerd allegations.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Overall, meeting so many people and seeing so much stuff in the span of three nights was overwhelming but also great. The Internet Archive rules, man.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Finally, literally last night, I met with &#x3C;a href=&#x22;https://nickyflowers.com/&#x22;&#x3E;Nicky&#x3C;/a&#x3E; to give &#x3C;a href=&#x22;https://damien.zone/bay-area-cohost-wake/&#x22;&#x3E;cohost 2&#x3C;/a&#x3E; back to them. We then hung out at the &#x3C;a href=&#x22;https://museemecanique.com/&#x22;&#x3E;Mus&#xE9;e M&#xE9;canique&#x3C;/a&#x3E;. Given the &#x22;touristy&#x22; status of the place, I feel like I should have heard about it a long time ago, but it was my first time there, and it was super neat! Digital stuff is cool, but there&#x27;s something just &#x3C;em&#x3E;neat&#x3C;/em&#x3E; about seeing mechanical contraptions, you know? Nicky took some cool pictures there, you should &#x3C;a href=&#x22;https://nickyflowers.com/blog/post_102724&#x22;&#x3E;check them out&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;hr /&#x3E;
&#x3C;p&#x3E;On the nerd side of things, I spent some part of my weekend tinkering with fonts and color stuff on the site. The notable changes are:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;background/text colors are warmer, especially in light mode.&#x3C;/li&#x3E;
&#x3C;li&#x3E;the headings are now using &#x3C;a href=&#x22;https://fonts.google.com/specimen/Young+Serif&#x22;&#x3E;Young Serif&#x3C;/a&#x3E; instead of Hack (a monospaced font) and, more importantly, are dark red anymore. As much as I like my deep-red accent color, it got old pretty quickly on the headings, in my opinion. I&#x27;m still keeping it for link underlines, at least for now.&#x3C;/li&#x3E;
&#x3C;li&#x3E;The Comentario buttons are also red now, yay.&#x3C;/li&#x3E;
&#x3C;li&#x3E;Other small details.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;I will most likely continue fucking around with the blog&#x27;s theme because that&#x27;s just how it goes, but this one felt significant enough to mention in a post.&#x3C;/p&#x3E;
&#x3C;p&#x3E;November should be much quieter, so hopefully I&#x27;ll be able to post more on here.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Have a good one!&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/end-of-october-2024-update&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>this blog has comments (again)</title>
          <link href="https://damien.zone/this-blog-has-comments-again" rel="alternate"/>
          <id>https://damien.zone/this-blog-has-comments-again</id>
          <published>2024-10-12T08:01:00Z</published>
          <updated>2024-10-12T09:39:40Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;Don&#x27;t adjust your RSS reader, you&#x27;re not seeing the same article twice. I just flip-flopped really hard with the whole comments thing.
In my (now unpublished) previous article, I said I went with &#x3C;a href=&#x22;https://chirpy.dev&#x22;&#x3E;Chirpy&#x3C;/a&#x3E; for comments... well, I&#x27;m not using them anymore! Oops! I am now using &#x3C;a href=&#x22;https://comentario.app/&#x22;&#x3E;Comentario&#x3C;/a&#x3E;! Comments are enabled on all posts, feel free to leave some!!&#x3C;br /&#x3E;
Sorry to those who already did &#x1F648;
Read below for the details of what happened here.&#x3C;/p&#x3E;
&#x3C;hr /&#x3E;
&#x3C;p&#x3E;It turns out Chirpy was pretty limiting in that commenters could not update their own avatar &#x3C;em&#x3E;at all&#x3C;/em&#x3E; if they didn&#x27;t sign in with GitHub/Twitter/Google... Which is extremely silly&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;.
I also wasn&#x27;t happy with the fact that its widget rendered inside an &#x3C;code&#x3E;&#x26;lt;iframe&#x26;gt;&#x3C;/code&#x3E; meaning customization options were limited to a few colors.&#x3C;/p&#x3E;
&#x3C;p&#x3E;This sent me down the path of finding alternatives. I had found a couple that seemed promising, but &#x3C;a href=&#x22;https://furry.engineer/@blaurascon&#x22;&#x3E;Blau&#x3C;/a&#x3E; on Mastodon made me aware of &#x3C;a href=&#x22;https://comentario.app&#x22;&#x3E;Comentario&#x3C;/a&#x3E; which... I think, is perfect for what I want?&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;&#x2705; Markdown formatting&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x2705; Comment replies&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x2705; Moderation UI/email notifications&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x2705; Custom user avatars&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x2705; Website field for authenticated users&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x2705; Anonymous posting (albeit limited)&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x2705; Authenticated posting
&#x3C;ul&#x3E;
&#x3C;li&#x3E;There are also options to set up login with Google/GitHub/GitLab/Twitter, but I didn&#x27;t dig into that just yet&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x2705; Does &#x3C;strong&#x3E;not&#x3C;/strong&#x3E; render within an &#x3C;code&#x3E;&#x26;lt;iframe&#x26;gt;&#x3C;/code&#x3E; element so I can tweak everything with CSS to make it look good with my theme! I need to actually tweak that, but the default theme is Good Enough&#x2122;&#xFE0F; for today.&#x3C;/li&#x3E;
&#x3C;li&#x3E;And a &#x3C;a href=&#x22;https://gitlab.com/comentario/comentario&#x22;&#x3E;bunch more features&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;The only downside being that there isn&#x27;t any way to set it up without hosting it yourself. This is fine for me because I know how to do it, but I know a bunch of people who would benefit from that solution who can&#x27;t/don&#x27;t want to self-host.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Therefore, I think a &#x22;friends of damien eggbug&#x22; shared instance of Comentario could be a good idea? If we know each other, and you are interested (and/or would like to help share the costs of a VPS + domain name&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-2&#x22; id=&#x22;user-content-fnref-2&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;2&#x3C;/a&#x3E;&#x3C;/sup&#x3E;), let&#x27;s get in touch.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I will probably keep my own instance because I have no clue if it can be migrated from a machine to another without breaking everything, but I want people to have access to that thing because I feel it might just be It? Maybe? We will see.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Oh, and also, if you&#x27;re interested in self-hosting it, I detailed my &#x3C;a href=&#x22;/my-comentario-self-hosting-setup/&#x22;&#x3E;setup here&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;See ya,&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;Thanks to &#x3C;a href=&#x22;https://zandravandra.com/&#x22;&#x3E;Zandra&#x3C;/a&#x3E; for the heads-up on this one, by the way. &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-2&#x22;&#x3E;
&#x3C;p&#x3E;If you can think of a good domain name, I&#x27;m also open to suggestions lol &#x3C;a href=&#x22;#user-content-fnref-2&#x22; data-footnote-backref aria-label=&#x22;Back to reference 2&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/this-blog-has-comments-again&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>link roundup for october 12th, 2024</title>
          <link href="https://damien.zone/link-roundup-for-october-12th-2024" rel="alternate"/>
          <id>https://damien.zone/link-roundup-for-october-12th-2024</id>
          <published>2024-10-12T07:00:00Z</published>
          <updated>2024-10-13T05:07:23Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;Stealing the &#x22;link roundup&#x22; format from &#x3C;a href=&#x22;https://jkap.io/&#x22;&#x3E;Jae&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://shelraphen.com/community-roundup-week-of-2024-09-22-28/&#x22;&#x3E;Shel&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://blog.dante.cool/&#x22;&#x3E;Dante&#x3C;/a&#x3E; and probably others I forget.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I want to try to make this a regular thing. I don&#x27;t expect the frequency to be consistent or anything, but still.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;cohost-memoriams&#x22;&#x3E;Cohost memoriams&#x3C;/h2&#x3E;
&#x3C;p&#x3E;As I write this, it has been almost two weeks since cohost went read-only. I still have many feelings about it. I do feel slightly less sad about it after having gone to the &#x3C;a href=&#x22;https://damien.zone/bay-area-cohost-wake/&#x22;&#x3E;Bay Area wake&#x3C;/a&#x3E;, though.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I could link to a dozen cohost eulogies and retrospectives. I liked &#x3C;a href=&#x22;https://shelraphen.com/cohost-eulogy-retrospective/&#x22;&#x3E;Shel&#x27;s&#x3C;/a&#x3E; one, and anything from &#x3C;a href=&#x22;https://blog.dante.cool/hello-again-and-for-the-first-time/&#x22;&#x3E;Dante&#x27;s roundup&#x3C;/a&#x3E; was also good. But here are a couple that, I think, are neat.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;bigg-building-a-house-of-cum&#x22;&#x3E;Bigg: &#x3C;a href=&#x22;https://www.bpgamesinc.com/building-a-house-of-cum/&#x22;&#x3E;Building A House Of Cum&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;The dissolution of a community is not value-neutral. I love my friends on Cohost&#x2019;s staff and am glad that they get to move on to better-paying jobs where they will not be subjected to hideous amounts of stress daily. However, it upsets me when I think that the unique, joyous culture Cohost nurtured around porn might disappear when the site goes offline at the end of the year. It&#x2019;s my dear, desperate hope that something about the experiences I&#x2019;ve shared here will be useful to future porn community-builders.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;h3 id=&#x22;cereza-a-farewell-to-cohostorg&#x22;&#x3E;cereza: &#x3C;a href=&#x22;https://cereza.bearblog.dev/a-farewell-to-cohostorg/&#x22;&#x3E;a farewell to cohost.org&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;i know i&#x27;m not the only one, i&#x27;ve seen a few artists who never posted online going on cohost and posted their art for the first time online. . i&#x27;m confident we&#x27;re gonna see artists, writers, whathaveyou in the coming years who will point to cohost as where they started out.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;h3 id=&#x22;msd-quailblog-closing-night-at-the-cohost-stage&#x22;&#x3E;msd (quailblog): &#x3C;a href=&#x22;https://blog.curiousquail.com/closing-night-at-the-cohost-stage/&#x22;&#x3E;Closing night at the Cohost Stage&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;Cohost meant a lot to a lot of people. To me, it meant this. A place I could see my friends art and not be bogged down with a lot of outside pressures. I don&#x27;t know that I&#x27;ll get that elsewhere online and it&#x27;s honestly ok if I don&#x27;t. I&#x27;m glad it existed. And if the closure results in tons of house shows (read: blogs and RSS renaissance) so be it.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;h3 id=&#x22;lena-raine-been-thinking-about-tangible-reality&#x22;&#x3E;Lena Raine: &#x3C;a href=&#x22;https://blog.radicaldream.land/been-thinking-about-tangible-reality/&#x22;&#x3E;been thinking about tangible reality&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;sometimes it doesn&#x27;t matter. sometimes it&#x27;s good. for the better. moving on and into a better frame of mind. a different space. a better space.&#x3C;/p&#x3E;
&#x3C;p&#x3E;sometimes it&#x27;s just sad.&#x3C;/p&#x3E;
&#x3C;p&#x3E;the people are the same, but the air is different. the imperceptible change in the intangible unreality makes everything feel slightly off. hairs raised just a bit. on edge. restless.&#x3C;/p&#x3E;
&#x3C;p&#x3E;we&#x27;ll probably be okay.&#x3C;/p&#x3E;
&#x3C;p&#x3E;but i&#x27;ll still miss it.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;h3 id=&#x22;maddie-lets-do-laundry-together-goodbye-cohost&#x22;&#x3E;Maddie: &#x3C;a href=&#x22;https://ninecoffees.blog/lets-do-laundry-together-goodbye-cohost/&#x22;&#x3E;Let&#x27;s Do Laundry Together (Goodbye Cohost)&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;You have to be kind and empathetic and you have to love. God, you have to love something. Be a pervert, if you have to, I certainly am. You have to find joy no matter how dire the circumstances because otherwise this world will break you. It is such a beautiful feeling to love and be loved, and there is no way to achieve that through force, no matter how many people delude themselves otherwise.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;h3 id=&#x22;sapkaer-cohost-this-is-the-end-and-a-new-beginning&#x22;&#x3E;Sapkaer: &#x3C;a href=&#x22;https://tempest.bearblog.dev/the-end-of-cohost-or-is-it/&#x22;&#x3E;Cohost. This is the end, and, a new beginning.&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;Maybe the cohost spirit is not about the website, or eggbug, or the CSS crimes, or the memes, or the lack of metrics.
Maybe the cohost spirit is simply about learning who you are, being true to yourself, and - most importantly, this is the part you should not skip - caring for others who are trying to do the same, so that you, them, all of us, can be a little more free to be ourselves.
Be not afraid to care. You could mean the world to someone else.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;h2 id=&#x22;cool-stuff-ive-seen-or-read&#x22;&#x3E;Cool stuff I&#x27;ve seen or read&#x3C;/h2&#x3E;
&#x3C;h3 id=&#x22;ticky-feed-buttons&#x22;&#x3E;Ticky: &#x3C;a href=&#x22;https://drac.at/posts/2024-10-04-feed-buttons/&#x22;&#x3E;Feed Buttons&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Ticky made some lovely 88x31 buttons to advertise that your website has an RSS feed. They&#x27;re great.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;shel-raphen-on-content-warnings&#x22;&#x3E;Shel Raphen: &#x3C;a href=&#x22;https://shelraphen.com/on-content-warnings/&#x22;&#x3E;On Content Warnings&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;I am going to rotate content warnings around like an object, cast upon in different lights, and examine their various implementations, justifications, and effects on online spaces in particular. I hope to locate a balanced dialectic on content warning best practices.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;Excellent article from Shel about content warnings. Like other folks, I realized, after the fact, that cohost&#x27;s implementation of that feature was smart and &#x3C;em&#x3E;man&#x3C;/em&#x3E;, going back to Mastodon feels archaic in comparison.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;yellowafterlife-some-of-the-css-crimes-of-all-time&#x22;&#x3E;yellowafterlife: &#x3C;a href=&#x22;https://yal.cc/cohost-css-crimes/&#x22;&#x3E;Some of the CSS crimes of all time&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;CSS crimes were one of these &#x22;features&#x22; that made cohost special in my heart. I hope other websites are implemented in a way that we might see this practice pop-up elsewhere, but in an age where customization and expression is limited on the Web, CSS crimes always felt like a breath of fresh air and a fantastic avenue for creativity.&#x3C;br /&#x3E;
This is a wonderful collection of some of the best crimes that people posted on cohost. I expect I will come back to this_page often.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;blackle-mori-interpolatable-colour-inversion&#x22;&#x3E;Blackle Mori: &#x3C;a href=&#x22;https://suricrasia.online/blog/interpolatable-colour-inversion/&#x22;&#x3E;Interpolatable Colour Inversion&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Shaders are one of these things I tried to learn multiple times over the years, and failed to do so, so it&#x27;s always fascinating to read about what they can do. Blackle&#x27;s solution to this problem is super smart and interesting to read about.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;misty-jingle-cats&#x22;&#x3E;Misty: &#x3C;a href=&#x22;http://cdrom.ca/games/2024/09/30/jingle-cats.html&#x22;&#x3E;Jingle Cats&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Misty&#x27;s CD-ROM Journal is great, you should read it. But obviously this article is great because, well, it&#x27;s about a game that simulates cats somewhat accurately and it sounds delightful. Makes me wonder why we don&#x27;t see those kinds of games as much anymore, you&#x27;d think we can simulate cats even better now!&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;erik-bernhardsson-its-hard-to-write-code-for-computers-but-its-even-harder-to-write-code-for-humans&#x22;&#x3E;Erik Bernhardsson: &#x3C;a href=&#x22;https://erikbern.com/2024/09/27/its-hard-to-write-code-for-humans&#x22;&#x3E;It&#x27;s hard to write code for computers, but it&#x27;s even harder to write code for humans&#x3C;/a&#x3E;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Excellent article about API design. It may sound daunting if you&#x27;re not a programmer, but I think a lot of its points can be mapped to other fields, so I recommend reading it!&#x3C;/p&#x3E;
&#x3C;hr /&#x3E;
&#x3C;p&#x3E;That&#x27;s all folks!&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/link-roundup-for-october-12th-2024&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>New thing: Friends of eggbug visualizer</title>
          <link href="https://damien.zone/new-thing-friends-of-eggbug-visualizer" rel="alternate"/>
          <id>https://damien.zone/new-thing-friends-of-eggbug-visualizer</id>
          <published>2024-10-09T02:27:00Z</published>
          <updated>2024-10-11T01:44:29Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/friends-of-eggbug/20-fullpage.webp&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/friends-of-eggbug/20-fullpage.webp&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Cohost started to send data exports to users. As soon as I got mine last night, I went to look at my &#x22;find my friends&#x22; page. It&#x27;s very convenient! But unfortunately, I don&#x27;t really like looking at tables for that stuff...&#x3C;/p&#x3E;
&#x3C;p&#x3E;So, of course, I wrote a tool to scratch that itch. It&#x27;s called &#x22;Friends of eggbug visualizer&#x22;&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;, it works in the browser, no data is sent anywhere, and it keeps your list in your browser&#x27;s own storage. This way you can import your &#x3C;code&#x3E;find-your-friends.json&#x3C;/code&#x3E; file once, and keep coming back to the list later on to go through your list.&#x3C;/p&#x3E;
Check it out at &#x3C;a href=&#x22;https://friends-of-eggbug.vercel.app/&#x22;&#x3E;https://friends-of-eggbug.vercel.app/&#x3C;/a&#x3E;!
&#x3C;p&#x3E;The source code is available on &#x3C;a href=&#x22;https://github.com/eramdam/friends-of-eggbug/&#x22;&#x3E;GitHub&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Cheers,&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;I still suck at finding names &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/new-thing-friends-of-eggbug-visualizer&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Bay Area Cohost Wake</title>
          <link href="https://damien.zone/bay-area-cohost-wake" rel="alternate"/>
          <id>https://damien.zone/bay-area-cohost-wake</id>
          <published>2024-10-06T07:00:00Z</published>
          <updated>2024-10-07T04:42:50Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;figure data-type=&#x22;image&#x22;&#x3E;
&#x3C;img src=&#x22;https://damien.zone/img/blog/img_7694.webp&#x22; alt=&#x22;A custom eggbug made by Beth out of foam clay, acrylic paint, mod podge and armature wire&#x22; /&#x3E;
&#x3C;figcaption&#x3E;A custom eggbug made by &#x3C;a href=&#x22;https://bsky.app/profile/bethposting.bsky.social&#x22;&#x3E;Bethposting&#x3C;/a&#x3E; out of foam clay, acrylic paint, mod podge and armature wire&#x3C;/figcaption&#x3E;
&#x3C;/figure&#x3E;
&#x3C;p&#x3E;For the longest time, on cohost, I kept saying &#x22;man, I should try to organize &#x3C;em&#x3E;something&#x3C;/em&#x3E; to meet up with the Bay Area folks&#x22;.&#x3C;br /&#x3E;
It almost became a running gag because I would post about it, and never act on it for many reasons. So when the shutdown of cohost was &#x3C;a href=&#x22;https://cohost.org/staff/post/7611443-cohost-to-shut-down&#x22;&#x3E;announced&#x3C;/a&#x3E;, and after seeing the &#x3C;a href=&#x22;https://nex-3.com/blog/seattle-cohost-wake/&#x22;&#x3E;Seattle&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://cohost.org/shel/post/7893527-at-the-philly-cohost&#x22;&#x3E;Philly&#x3C;/a&#x3E; &#x22;cohost wakes&#x22; being planned, I went &#x22;fuck it, we ball&#x22;.&#x3C;br /&#x3E;
I posted about it, people said they&#x27;d be interested, &#x3C;a href=&#x22;https://nickyflowers.com/&#x22;&#x3E;Nicky&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://cohost.org/diane?page=0&#x22;&#x3E;Diane&#x3C;/a&#x3E; helped me actually find a spot and time, and I &#x3C;a href=&#x22;https://cohost.org/eramdam/post/7750903-yeah-sf-bay-area&#x22;&#x3E;announced it&#x3C;/a&#x3E;. I was diligently keeping track of who had replied and how, to have an at least vague idea of how many people would show up.&#x3C;/p&#x3E;
&#x3C;p&#x3E;18 days later, earlier today as I write this: we had &#x3C;strong&#x3E;40 people&#x3C;/strong&#x3E; show up!! I don&#x27;t actually have a group picture to show because I wasn&#x27;t the one who took them and not everyone wants to be visible publicly in such a picture, so you&#x27;ll have to take my word for it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;In fact, I barely had any time to take many pictures myself! The only ones I have are of &#x3C;a href=&#x22;/img/blog/img_7695-2.webp&#x22;&#x3E;Cohost 2&#x3C;/a&#x3E;, a huge scroll of paper that Nicky brought so we could make posts by hand.&#x3C;br /&#x3E;
It was a lot of fun, wish I took more pictures. But I feel chatting with people, recognizing folks from the website and having a good time was more important than taking pictures, you know?&#x3C;/p&#x3E;
&#x3C;p&#x3E;People hung out, some of them played a fighting game with specialized controllers&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;, people talked about the website, nerd shit, linguistics, and a bunch of other things. Emails were gathered so people could organize and try to make this a more recurring thing, now that we know we can motivate at least &#x3C;em&#x3E;some&#x3C;/em&#x3E; people to meet up.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Cohost really was &#x3C;a href=&#x22;https://web.archive.org/web/20240916171700/https://cohost.org/lukedotorg/post/234549-it-s-like-a-website&#x22;&#x3E;like a website&#x3C;/a&#x3E;, it was a website that somehow got us to actually touch grass and is making us think about touching more grass in the future. And I think that&#x27;s really neat.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Eggbug forever,
- damien&#x3C;/p&#x3E;
&#x3C;p&#x3E;P.S: if you were there and have pictures you&#x27;re willing to share with me, I&#x27;d love to see them! Email me at &#x3C;a href=&#x22;mailto:damien@erambert.me&#x22;&#x3E;damien@erambert.me&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;I know these weren&#x27;t sticks, but I&#x27;m also a fighting game noob lmao &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/bay-area-cohost-wake&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Justice at Portola 2024</title>
          <link href="https://damien.zone/justice-at-portola-2024" rel="alternate"/>
          <id>https://damien.zone/justice-at-portola-2024</id>
          <published>2024-10-01T00:25:00Z</published>
          <updated>2024-10-01T00:48:10Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;Well, it turns out I was pretty lucky because Justice&#x27;s show last night (September 29th) was a very very good one in terms of pictures! I got literally as close as one could realistically be, even if I was slightly off center!&#x3C;/p&#x3E;
&#x3C;p&#x3E;As I got out of the show, I was pretty worried because Justice&#x27;s light setup made it much, &#x3C;em&#x3E;much&#x3C;/em&#x3E; harder to get consistently good shots. Don&#x27;t get me wrong, those very quick color changes in the lights look amazing in person, but they are challenging to shoot with a smartphone.&#x3C;/p&#x3E;
&#x3C;p&#x3E;But I think I managed to get some pretty damn good pictures given the situation. Like those taken during &#x3C;a href=&#x22;/shot-on-iphone-with-halide-gesaffelstein-at-portola-2024/&#x22;&#x3E;Gesaffelstein&#x27;s performance&#x3C;/a&#x3E;, &#x3C;strong&#x3E;all of them&#x3C;/strong&#x3E; were shot with Halide and in RAW with &#x22;Process Zero&#x22; enabled. The only adjustments I made (if any) are cropping and slight tweaks to the exposure/contrast.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Everything else is straight out of the iPhone 13 Pro&#x27;s camera system. Which, for some of them, is outstanding to see, honestly. As always, click the thumbnails to get the JPEG at 100% quality.&#x3C;/p&#x3E;
&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_6962 1 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_6962 1 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;
&#x3C;div class=&#x22;gallery&#x22;&#x3E;
  &#x3C;ul&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7071 2 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7071 2 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7073 3 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7073 3 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7081 4 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7081 4 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7085 5 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7085 5 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7089 6 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7089 6 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7092 7 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7092 7 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7103 8 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7103 8 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7117 9 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7117 9 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7125 10 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7125 10 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7165 11 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7165 11 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7317 12 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7317 12 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7319 13 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7319 13 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7453 14 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7453 14 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7464 15 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7464 15 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7467 16 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7467 16 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7468 17 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7468 17 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7494 18 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7494 18 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7506 19 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7506 19 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/justice-2024/IMG_7539 20 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/justice-2024/thumbs/IMG_7539 20 Edited.jpg&#x22; alt=&#x22;&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
  &#x3C;/ul&#x3E;
&#x3C;/div&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/justice-at-portola-2024&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>shot on iPhone with Halide: Gesaffelstein at Portola 2024</title>
          <link href="https://damien.zone/shot-on-iphone-with-halide-gesaffelstein-at-portola-2024" rel="alternate"/>
          <id>https://damien.zone/shot-on-iphone-with-halide-gesaffelstein-at-portola-2024</id>
          <published>2024-09-29T20:01:00Z</published>
          <updated>2024-09-30T22:09:11Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;I just saw Gesaffelstein last night at &#x3C;a href=&#x22;https://portolamusicfestival.com/&#x22;&#x3E;Portola&#x3C;/a&#x3E; and &#x3C;strong&#x3E;boy&#x3C;/strong&#x3E; that shit ripped. I had already watched his set from Coachella earlier this year, so I &#x22;knew&#x22; what to expect. But as always, watching a live performance is one thing, &#x3C;strong&#x3E;being&#x3C;/strong&#x3E; there in person is another.&#x3C;/p&#x3E;
&#x3C;p&#x3E;A true banger of a show, the combination of the minimalist set design and the &#x3C;a href=&#x22;https://www.youtube.com/watch?v=4HnUmZOjsyU&#x22;&#x3E;hard hitting music&#x3C;/a&#x3E; really really worked.&#x3C;/p&#x3E;
&#x3C;p&#x3E;As I often do in concerts, I took plenty of pictures/videos. It took me a few hours to triage everything (because Darkroom on macOS kind of sucks) but I managed to trim it down to a reasonable amount.&#x3C;/p&#x3E;
&#x3C;p&#x3E;All of these were taken on my iPhone 13 Pro using the 3x telephoto lens. The first three ones were taken with the stock iOS camera, all the others were shot using &#x3C;a href=&#x22;https://halide.cam/&#x22;&#x3E;Halide&#x3C;/a&#x3E; in RAW with &#x3C;a href=&#x22;https://www.lux.camera/introducing-process-zero-for-iphone/&#x22;&#x3E;&#x22;Process Zero&#x22; mode&#x3C;/a&#x3E; enabled.&#x3C;br /&#x3E;
And honestly? It produced incredible results given that: this is a phone camera, at a music festival, taken by hand&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E; in a low-light environment.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Halide (in RAW mode) was already a killer tool for concert photography in my experience but Process Zero really takes it to the next level. The capture speed was more than enough, turns out when your camera doesn&#x27;t try to capture hundreds of frame for &#x3C;em&#x3E;one&#x3C;/em&#x3E; shot, you can go pretty wild with it. The focus was a bit hit or miss but that&#x27;s expected given the environment (the fog machines really didn&#x27;t help haha).&#x3C;/p&#x3E;
&#x3C;p&#x3E;I only had to adjust the exposure/brightness on a handful of shots! It&#x27;s incredible, really. I hope to be able to take good shots of Justice tonight &#x1F91E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;At any rate, here are the pictures (click to load the full, uncompressed JPEGs):&#x3C;/p&#x3E;
&#x3C;div class=&#x22;gallery&#x22;&#x3E;
  &#x3C;ul&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6415 1 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6415 1 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6447 2 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6447 2 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6497 3 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6497 3 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6535 4 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6535 4 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6540 5 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6540 5 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6546 6 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6546 6 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6558 7 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6558 7 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6568 8 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6568 8 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6577 9 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6577 9 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6578 10 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6578 10 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6585 11 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6585 11 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6589 12 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6589 12 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6628 13 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6628 13 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6644 14 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6644 14 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6646 15 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6646 15 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6686 16 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6686 16 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
    &#x3C;li&#x3E;&#x3C;figure&#x3E;&#x3C;a href=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/IMG_6719 17 Edited.jpg&#x22;&#x3E;&#x3C;img loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; src=&#x22;https://damiensfiles.b-cdn.net/gesaffelstein-2024/thumbs/IMG_6719 17 Edited.jpg&#x22; alt=&#x22;Gesaffelstein on stage at Portola&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;/figure&#x3E;&#x3C;/li&#x3E;
  &#x3C;/ul&#x3E;
&#x3C;/div&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;I had a fence to stabilize, but it wasn&#x27;t much &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/shot-on-iphone-with-halide-gesaffelstein-at-portola-2024&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>my online life, and cohost</title>
          <link href="https://damien.zone/my-online-life-and-cohost" rel="alternate"/>
          <id>https://damien.zone/my-online-life-and-cohost</id>
          <published>2024-09-28T07:00:00Z</published>
          <updated>2024-10-02T06:44:14Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;&#x3C;em&#x3E;This post is mirrored on cohost as well and was written with it in mind. But also not? It&#x27;s fine, don&#x27;t worry about it.&#x3C;/em&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Like many people in my age group, I think it&#x27;s fair to say that I grew up online.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;the-pre-social-media-years&#x22;&#x3E;the pre-social media years&#x3C;/h3&#x3E;
&#x3C;p&#x3E;My &#x22;life online&#x22; really started in the mid-2000s when I joined the forums of &#x3C;a href=&#x22;https://web.archive.org/web/20060314072844/http://www.crystalxp.net/&#x22;&#x3E;Crystal XP&#x3C;/a&#x3E;. This name probably won&#x27;t mean anything to you, but if you used Windows XP at the time, you might have seen their &#x22;&#x3C;a href=&#x22;https://web.archive.org/web/20060314073432/http://www.crystalxp.net/bricopack/en.htm&#x22;&#x3E;BricoPacks&#x3C;/a&#x3E;&#x22;. These were 1-click installers that reskinned your entire Windows installation. Their most successful one was the &#x3C;a href=&#x22;https://web.archive.org/web/20060314073432/http://www.crystalxp.net/bricopack/en.htm&#x22;&#x3E;Vista Inspirat&#x3C;/a&#x3E; one. Pretty wild stuff. Oh, and also CrystalXP was &#x22;responsible&#x22; for &#x3C;a href=&#x22;https://web.archive.org/web/20060314081445/http://www.crystalxp.net/tuto/en19-make-a-g2-tux-with-adobe-photoshop.html&#x22;&#x3E;that one Tux&#x3C;/a&#x3E; and its myriad of variations you might see on every other Linux fanboy&#x27;s profile.&#x3C;/p&#x3E;
&#x3C;p&#x3E;But like I said, they had forums. I joined those forums after reading CrystalXP&#x27;s Photoshop tutorials and wanting to share my progress and get advice. I met a bunch of people, some of whom I am still friends with to this day, learned a ton about graphic and UI design.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I drew icons, wallpapers, all of varying quality that I would post to my DeviantArt profile.&#x3C;br /&#x3E;
I went &#x3C;em&#x3E;hard&#x3C;/em&#x3E; into the Windows customization bit. At first, it was simple stuff, but around 2006-2007, I got enamored by Mac OS X&#x27;s UI from watching a friend&#x27;s Mac screenshots.&#x3C;br /&#x3E;
From this point on, my goal was to make Windows XP look like Mac OS X (Tiger and then Leopard). I wish I still had those &#x22;desks&#x22; screenshots because &#x3C;em&#x3E;man&#x3C;/em&#x3E;, I was good at that shit. I made skins for iTunes, a skin for &#x3C;a href=&#x22;https://www.stardock.com/blog/499789/remember-objectbar-i-tried-it-on-windows-10&#x22;&#x3E;ObjectBar&#x3C;/a&#x3E; that mimicked the Leopard menubar, skins for &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Miranda_NG&#x22;&#x3E;Miranda IM&#x3C;/a&#x3E; that copied &#x3C;a href=&#x22;https://adium.im/&#x22;&#x3E;Adium&#x3C;/a&#x3E; skins.&#x3C;/p&#x3E;
&#x3C;p&#x3E;A year later, I would get my first Mac. A 24&#x22; Aluminum iMac, running Mac OS X Leopard. That computer and its software felt like a candy store to me. So many good details, so much whimsy, and... dude the customization options were bonkers.&#x3C;br /&#x3E;
Sadly, &#x3C;a href=&#x22;https://www.macintoshrepository.org/11531-shapeshifter-osx-theming-&#x22;&#x3E;ShapeShifter&#x3C;/a&#x3E; was already defunct. Even then, apps like &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/CandyBar&#x22;&#x3E;CandyBar&#x3C;/a&#x3E; and websites like the &#x3C;a href=&#x22;https://iconfactory.com/&#x22;&#x3E;IconFactory&#x3C;/a&#x3E; and their amazing icons, wallpapers and skins were incredible resources.&#x3C;br /&#x3E;
Obviously, like any Mac user of that era, I ended up on forums like &#x3C;a href=&#x22;https://web.archive.org/web/20100304153810/http://macthemes.net/&#x22;&#x3E;MacThemes.net&#x3C;/a&#x3E;. I was still messing around with Photoshop, so I kept learning a lot.&#x3C;/p&#x3E;
&#x3C;p&#x3E;But at that point, I was more into UI and web design than anything else. I made skins for apps like &#x3C;a href=&#x22;http://bowtieapp.com/&#x22;&#x3E;Bowtie&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Ecoute&#x22;&#x3E;Ecoute&#x3C;/a&#x3E;, I made a theme for Leopard I can&#x27;t find traces of (&#x22;Disinmaso for Leopard&#x22;, if someone finds it), I made a &#x3C;a href=&#x22;https://www.macstories.net/mac/want-itunes-9-look-back-theres-a-mod-for-that/&#x22;&#x3E;mod for iTunes 10 that brought back the iTunes 9 colors back&#x3C;/a&#x3E;, and a skin for &#x3C;a href=&#x22;/img/blog/vlc-better-by-default.jpg&#x22;&#x3E;VLC media player&#x3C;/a&#x3E;. More on that bit later.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;the-twitter-years&#x22;&#x3E;the twitter years&#x3C;/h3&#x3E;
&#x3C;p&#x3E;In parallel, I would join Twitter in like? 2009? Early enough that Twitter still:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;had a global timeline&#x3C;/li&#x3E;
&#x3C;li&#x3E;had no retweets&#x3C;/li&#x3E;
&#x3C;li&#x3E;had background images and personal accent colors for profiles&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;So whatever year it was, it was pretty early. It was early enough that I probably was around the first few thousands of French users on the site. Twitter was really nerdy and niche at the time. And it ruled.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I probably was too young (~16) to be visible on Twitter, but I was, at a tiny level but still. I got involved enough to personally be blocked by a semi-famous French tech blogger, I made tons of friends by just posting-way-too-much. Likewise, I also made enemies by just being a stupid teenager on Twitter.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Twitter also got me a ton of work. I got close with one of the friends I met on CrystalXP, and we ended up making a tiny structure to take web design jobs/projects from folks. I met and &#x22;networked&#x22; with many older folks in the design/tech space. Some of whom I admired, some of whom became friends, some of whom helped me get my current job.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Without Twitter, I wouldn&#x27;t have met some of my closest friends.&#x3C;br /&#x3E;
Without Twitter, I wouldn&#x27;t have worked with VideoLAN on &#x3C;a href=&#x22;https://www.macstories.net/news/vlc-2-0-for-mac-final-design-previewed-coming-this-week/&#x22;&#x3E;VLC 2 for Mac OS X&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://www.macstories.net/news/vlc-for-ios-returns-to-the-app-store/&#x22;&#x3E;iOS&#x3C;/a&#x3E;.&#x3C;br /&#x3E;
Without Twitter, I literally would not be typing this blog post 9,000 kilometers away from the French city I was born in.
And of course, without Twitter, TweetDeck wouldn&#x2019;t exist and... I wouldn&#x27;t have started &#x3C;a href=&#x22;https://better.tw&#x22;&#x3E;Better TweetDeck&#x3C;/a&#x3E; in 2014.&#x3C;/p&#x3E;
&#x3C;p&#x3E;In the middle of 2015, I moved to San Francisco. A year later, Donald Trump would get elected president. Twitter died a first time on that day.
Twitter suddenly became &#x3C;em&#x3E;serious&#x3C;/em&#x3E; (derogatory), it was now the most powerful man on Earth&#x27;s megaphone, and posting on it meant there was a non-zero chance of being noticed either by him or his army of bigoted fans.
I would still use Twitter (and still do) for years to come, but a tone shift had happened. Twitter felt like it became a PVP zone.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;mastodon-enters-the-chat&#x22;&#x3E;mastodon enters the chat&#x3C;/h3&#x3E;
&#x3C;p&#x3E;In the middle of 2017, a new social media platform called Mastodon started picking up steam. Its main selling point was &#x22;it&#x27;s like Twitter but with decent moderation, open-source and decentralized&#x22;.&#x3C;br /&#x3E;
Being the nerd that I am, I joined it. I saw genuine promise in Mastodon. I would &#x3C;a href=&#x22;https://github.com/mastodon/mastodon/commits?author=eramdam&#x22;&#x3E;contribute&#x3C;/a&#x3E; to the project&#x27;s codebase, I was on the Discord/Patreon for a while, I briefly helped moderate mastodon.social. I would get kicked off the Patreon/Discord for basically shit talking Eugen&#x27;s direction of the project. Which is fair, I was being a jerk!&#x3C;br /&#x3E;
I still think that &#x22;well, you can fork the project&#x22; is an embarrassing answer to give to users who wanted to see Mastodon get better, but what do I know.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I still think Mastodon is a good idea and is something that needs to exist, but I rapidly felt that... its approach was kind of flawed?&#x3C;br /&#x3E;
Eugen will deny this, but I, and other folks, realized early on that his &#x22;Benevolent Dictator For Life&#x22; approach of managing the project pushed away &#x3C;em&#x3E;many&#x3C;/em&#x3E; people who were willing to improve the software.&#x3C;/p&#x3E;
&#x3C;p&#x3E;But all the code in the world cannot fix what was (and still is), in my opinion, Mastodon/the Fediverse&#x27;s biggest hurdle: community and moderation.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Without rehashing how Mastodon works (thousands of articles do it better than I do): the main idea is that instances host their users and have their own moderation/content policies. On paper this sounds good because what may work for me moderation-wise may not work for you and vice versa. In practice? It was and still is a mixed bag at best and a fucking shitshow at worst.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Turns out, the people who can run a web server are usually not fit to run a community and probably shouldn&#x27;t be trusted to take moderation decisions. I have seen dozens of instances fall apart or get cut off the rest of the network because of interpersonal drama, laughable moderation practices, malicious actors, bigotry, racism, and a lot more.&#x3C;/p&#x3E;
&#x3C;p&#x3E;This whole structural issue and the fact that Mastodon has been, and still is, &#x3C;em&#x3E;complicated&#x3C;/em&#x3E; to get for non-nerds meant that I had little hope that it would ever replace Twitter. This wouldn&#x27;t be so annoying if Mastodon as a project wasn&#x27;t so set on courting Twitter users and imitating Twitter. But that could be its own essay.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I would still use Twitter in parallel, and it would be my main place. Having TweetDeck and Better TweetDeck meant that, despite everything, I could &#x3C;em&#x3E;shape&#x3C;/em&#x3E; my experience on Twitter however I wanted (to a degree).&#x3C;/p&#x3E;
&#x3C;p&#x3E;If I didn&#x27;t have that? Who knows, perhaps Mastodon would have become my &#x22;first website&#x22; instead of my &#x22;second website where most of the nerds
are, and also everything is on fire every other week&#x22;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Despite all the shit I talked about Mastodon in the previous paragraphs, I still used it a lot and met a lot of nice people there. Some of them were running (large) Mastodon instances, some of them even contributed in big ways to Mastodon&#x27;s codebase. Most of them would agree with me that &#x22;Mastodon existing is a net good, but Mastodon as it stands is kind of a mess&#x22; (to be charitable).&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;here-comes-an-eggbug&#x22;&#x3E;here comes an eggbug&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Some people I met on Mastodon became close friends. As it turned out, some of them were close to &#x3C;a href=&#x22;https://antisoftware.club/&#x22;&#x3E;ASSC&#x3C;/a&#x3E;.&#x3C;br /&#x3E;
In April 2022, I would get invited by &#x3C;a href=&#x22;https://jkap.io&#x22;&#x3E;jkap&#x3C;/a&#x3E; to try &#x3C;a href=&#x22;https://cohost.org&#x22;&#x3E;cohost&#x3C;/a&#x3E;. I&#x27;m genuinely grateful for that because &#x3C;em&#x3E;man&#x3C;/em&#x3E;. I will miss that place.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I would say I was &#x22;hooked&#x22; right away but, as much as some of cohost&#x27;s design principles were very appealing, I&#x2026; didn&#x27;t really &#x3C;em&#x3E;&#x22;get&#x22;&#x3C;/em&#x3E; it right away? I was still very much into microblogging for a while. And the limited beta meant that the user base was still small. The place would get progressively more interesting to me after launch onwards.&#x3C;/p&#x3E;
&#x3C;p&#x3E;But what really flipped a switch in my head was Elon Musk&#x27;s acquisition of Twitter. We knew it was going to happen, but it still felt terrible. I didn&#x27;t even particularly care about the website itself because it had been on a downhill trajectory for a while, but... seeing this fucking guy buy the company, fire 90% of the staff, and take the whole thing apart like a capricious toddler was disappointing.&#x3C;br /&#x3E;
I was disappointed to realize we lived in a world where this kind of shit could even happen, you know?&#x3C;/p&#x3E;
&#x3C;p&#x3E;Suddenly, my &#x3C;em&#x3E;first&#x3C;/em&#x3E; website was getting worse by the week, (some) people started flocking to Mastodon but... I had been on Mastodon for half a decade at that point, so I didn&#x27;t have it in me to be starry-eyed about Mastodon again. I was happy people were leaving the &#x3C;em&#x3E;hellsite&#x3C;/em&#x3E;, but still.&#x3C;/p&#x3E;
&#x3C;p&#x3E;So I started using cohost a lot more. And, man, I should have done it sooner. It is now clearer than ever in my head now but: cohost fixed something in my brain that Twitter/Mastodon broke.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Cohost was the slow, relaxing, composed, and fun alternative to the &#x22;Player versus Player&#x22; environment of Mastodon, Twitter and Bluesky (when that became more of a thing a few months later).&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;the-bluesky-interlude&#x22;&#x3E;the bluesky interlude&#x3C;/h3&#x3E;
&#x3C;p&#x3E;In March 2023, I would end up getting an invite to Bluesky from a friend who was on there. I was curious to check it out. I knew I wasn&#x27;t going to fall in love with it because the &#x22;decentralization&#x22; story didn&#x27;t interest me anymore and because it sprung out of Jack Dorsey&#x27;s Twitter.&#x3C;br /&#x3E;
But man, I didn&#x27;t expect Bluesky to disappoint me &#x3C;em&#x3E;so quickly&#x3C;/em&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I know I am going to piss off a bunch of &#x22;Bluesky elders&#x22; (ugh) by saying this, but: Bluesky walked on rakes early, and still to this day continues to walk on rakes.&#x3C;br /&#x3E;
I have been on the website for longer than 99% of the user base, so I have &#x3C;em&#x3E;seen&#x3C;/em&#x3E; some bullshit.&#x3C;br /&#x3E;
The invite-only system led to, frankly, worrying levels of &#x22;crabs in the bucket&#x22; thinking and some unhealthy levels of parasocial relationships because &#x22;invite-only = private, right?&#x22;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;And I don&#x27;t know, man, I refuse to fully trust a VC-backed social media company at this point. And my trust goes down every time they pretend that they &#x22;work for their users&#x22; and that they are &#x22;billionaire-proof&#x22;. Your codebase/app being open-source doesn&#x27;t mean a damn to me. It just makes it slightly easier for me to write a bot, but that&#x27;s kind of it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;If you got millions in the bank, hire people to improve the thing instead of relying on free labor to fill in your own gaps.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I could go on about Bluesky&#x27;s protocol (ATProto) or about how Bluesky&#x27;s libertarian-you-do-it-yourself approach to moderation is appalling to me. I won&#x27;t do it here because this post is already getting long but, yeah, I am not very enthusiastic about Bluesky.&#x3C;br /&#x3E;
I&#x27;m still on there, and I might use it more once cohost goes read-only. But man, &#x3C;a href=&#x22;https://youtu.be/YhiJX9CzT30?si=rYKOSOGtnh8g6ik0&#x26;amp;t=23&#x22;&#x3E;I&#x27;m gonna complain the whole time&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;i-will-miss-a-fucking-website&#x22;&#x3E;i will miss a fucking website&#x3C;/h3&#x3E;
&#x3C;p&#x3E;I&#x27;ve said as much on my different socials already, but... dude, I cried so fucking much after the shutdown of cohost was announced. I don&#x27;t cry that often! And yet! The week of September 9th saw me cry the most I&#x27;ve had ever cried in a very long time.&#x3C;/p&#x3E;
&#x3C;p&#x3E;At first, I cried from sadness because it was going away, then cried from anger because it couldn&#x27;t exist in our current system. Then the overwhelming feelings from the user base of &#x22;I will miss cohost&#x22; made me cry again. I cried because of a &#x3C;a href=&#x22;https://cohost.org/astr-hal/post/7633384-i-m-considering-gett&#x22;&#x3E;cute, reassuring, sweet, piece of art&#x3C;/a&#x3E;, I cried because of a &#x3C;a href=&#x22;https://cohost.org/curiousquail/post/7738599-what-we-leave-behind&#x22;&#x3E;&#x22;cohost meme song&#x22;&#x3C;/a&#x3E; that made me realize how many good jokes/memes the users made. I cried listening to a &#x3C;a href=&#x22;https://cohost.org/zandravandra/post/7728342-compost-6-see-you&#x22;&#x3E;very bittersweet, yet beautiful song&#x3C;/a&#x3E; about cohost ending.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I cried a lot. For a &#x3C;em&#x3E;website&#x3C;/em&#x3E;?!&#x3C;/p&#x3E;
&#x3C;p&#x3E;But obviously this wasn&#x27;t only about the website. I cried because I felt like I was losing a place I called home online.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I cried because I knew I was losing a truly special place in my heart, where I met wonderful new people, learned about so many interesting subjects, laughed at so many good jokes.&#x3C;/p&#x3E;
&#x3C;p&#x3E;cohost at times felt like my little &#x22;internet oasis&#x22;, it was where I would go when my other 3 websites felt exhausting. It was where folks I looked up to would be able to just... post? In peace?&#x3C;/p&#x3E;
&#x3C;p&#x3E;cohost was a place where I saw artists, photographers, musicians, makers, and creatives in general able to just &#x3C;em&#x3E;share their craft&#x3C;/em&#x3E; and usually get much better &#x22;return&#x22; on it than anywhere else!&#x3C;/p&#x3E;
&#x3C;p&#x3E;cohost felt much safer &#x3C;strong&#x3E;to me&#x3C;/strong&#x3E; than the other websites I used. I felt much safer in opening up about personal matters, I felt safer writing long form posts about my special interests. I felt safer knowing that, if a post sounded a bit too spicy, I could just not make it shareable and/or lock comments on it, and it would just be a blip in people&#x27;s feeds. And it was great!&#x3C;/p&#x3E;
&#x3C;p&#x3E;I know this wasn&#x27;t a universal experience, I have met people who got driven off the site due to (racist) harassment. I wish it wouldn&#x27;t have happened, I tried helping at my &#x22;level&#x22;, but ultimately a lot of the issues were not for me to fix.
And I&#x27;m sad about that because &#x3C;strong&#x3E;my&#x3C;/strong&#x3E; experience of cohost was wonderful, and I wish it was for more people.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I will miss the Posting energy of cohost, the camaraderie, the mascots (not just eggbug), the &#x3C;a href=&#x22;https://cohost.org/CoolTimesOnline/post/7640392-thank-you-cohost&#x22;&#x3E;&#x22;yes, and&#x22;&#x3C;/a&#x3E; spirit that lead to so many good jokes.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I will miss cohost&#x27;s staff. I didn&#x27;t agree with every decision they took, but I still have a massive amount of respect for them. It takes guts to stick to your vision, even if/when everybody tells you it&#x27;s foolish or stupid to not build a social media platform that doesn&#x27;t sell its users out while making them miserable.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The way they&#x27;re handling the shutdown is, frankly, embarrassing for everyone else in this industry.&#x3C;br /&#x3E;
I know damn well that when the next Mastodon instance shuts down, when Twitter blows up or when Bluesky explodes that none of them will care as much for their users&#x27; content and &#x3C;em&#x3E;connections&#x3C;/em&#x3E; as much as Cohost&#x27;s staff cares about cohost users.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I will miss a &#x3C;em&#x3E;fucking website&#x3C;/em&#x3E;, but damn, what a website it was.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;whats-next-for-me&#x22;&#x3E;what&#x27;s next for me&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Well. Chances are you might be reading this inside an RSS feed already, so this (&#x3C;a href=&#x22;https://damien.zone&#x22;&#x3E;https://damien.zone&#x3C;/a&#x3E;) is what&#x27;s next for me.&#x3C;br /&#x3E;
My relationship to microblogging/social media in general is gonna change, I think.&#x3C;br /&#x3E;
I am still going to use &#x3C;a href=&#x22;https://social.erambert.me/@eramdam&#x22;&#x3E;Mastodon&#x3C;/a&#x3E; for the &#x22;tiny posts&#x22; stuff. I might try to use &#x3C;a href=&#x22;https://bsky.app/profile/damien.zone&#x22;&#x3E;Bluesky&#x3C;/a&#x3E; more, especially since a bunch of cohost folks are following me there, but I am going to complain&#x2014;I made that joke already.&#x3C;br /&#x3E;
My &#x3C;a href=&#x22;https://twitter.com/Eramdam&#x22;&#x3E;Twitter account&#x3C;/a&#x3E; is still up. I locked it a few weeks ago, and I don&#x27;t think I will re-open it anytime soon, or maybe ever? Time will tell. Don&#x27;t expect me to post there very much.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I want to try to use social media less if I&#x27;m being honest. I&#x27;ve been using Discord and regular-ass instant messaging a lot more for the past few weeks. It&#x27;s been great to just be able to talk to more people. I am seeing a bunch of people from cohost and beyond in person in the coming weeks and months, I am looking forward to that. I collected some of my cohost mutuals&#x27; information, added them on Discord and other places. I know I missed some of you, I will try to do an exhaustive &#x22;sweep&#x22; when my data export with the &#x22;find your friends&#x22; page is available.&#x3C;/p&#x3E;
&#x3C;p&#x3E;cohost reminded me that the best part about using a website was the people you meet on it, so even if the website goes away, hopefully the connections you made will stay around.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Thank you, cohost, I will miss you a whole lot.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Cheers, have a good life, wherever y&#x27;all go. I hope we meet again soon,&#x3C;/p&#x3E;
&#x3C;p&#x3E;- damien&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/my-online-life-and-cohost&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>release notes, end of september 2024</title>
          <link href="https://damien.zone/release-notes-end-of-september-2024" rel="alternate"/>
          <id>https://damien.zone/release-notes-end-of-september-2024</id>
          <published>2024-09-27T01:00:00Z</published>
          <updated>2024-09-27T05:05:04Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;A little post to tell the folks who are only reading the RSS feed about what I&#x27;ve been up to on damien.zone:&#x3C;/p&#x3E;
&#x3C;p&#x3E;I got a &#x3C;a href=&#x22;https://damien.zone/links&#x22;&#x3E;links&#x3C;/a&#x3E; page with:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;my own links!&#x3C;/li&#x3E;
&#x3C;li&#x3E;nice buttons I keep seeing on people&#x27;s websites! I&#x27;ll try to collect more as time goes on&#x3C;/li&#x3E;
&#x3C;li&#x3E;I have a button too!! &#x3C;a href=&#x22;https://shadenexus.com/&#x22;&#x3E;Gwyn&#x3C;/a&#x3E; absolutely killed it, you can grab it on there as well&#x3C;/li&#x3E;
&#x3C;li&#x3E;friends&#x27; links and just cool links in general&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;I started a &#x3C;a href=&#x22;https://damien.zone/projects&#x22;&#x3E;projects&#x3C;/a&#x3E; page. It has &#x3C;em&#x3E;almost&#x3C;/em&#x3E; everything I would care about publicizing on here. The big thing missing are links for my Mac Themes bot that people enjoyed on cohost. I&#x27;ll remedy that. In the meantime, you can find the bot on &#x3C;a href=&#x22;https://botsin.space/@osxthemes&#x22;&#x3E;Mastodon&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://bsky.app/profile/macthemes.bsky.social&#x22;&#x3E;Bluesky&#x3C;/a&#x3E; as well as &#x3C;a href=&#x22;https://x.com/macintoshthemes&#x22;&#x3E;Twitter&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I have a &#x22;final cohost post&#x22; ready to send on next Monday (September 30th). I might mirror it here, we will see.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I have another, longer, &#x22;my online life&#x22; type post that I don&#x27;t think will be ready before cohost&#x27;s goes read-only. As luck would have it, I already had plans for this weekend, so I won&#x27;t have much time to spend on a computer before Monday. But I hope it&#x27;ll be at least slightly interesting when I&#x27;m done with it! The hardest part will be to edit myself to not write &#x3C;em&#x3E;too much&#x3C;/em&#x3E;, haha.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I also ported my old blog posts over to this blog. I don&#x27;t think they showed up on the RSS feed (at least I hope they didn&#x27;t) so, in case you weren&#x27;t aware:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;Better TweetDeck post-mortem &#x3C;a href=&#x22;https://damien.zone/bettertweetdeck-post-mortem-part-1-faq/&#x22;&#x3E;part one&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://damien.zone/bettertweetdeck-post-mortem-part-2/&#x22;&#x3E;part two&#x3C;/a&#x3E;. Part two is probably the one you&#x27;ll want to read in 2024.&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;a href=&#x22;https://damien.zone/intersection-of-liberal-arts-and-technology/&#x22;&#x3E;&#x22;The intersection of liberal arts and technology&#x22;&#x3C;/a&#x3E;. Kind of a rant/thinking out loud post I wrote at like, 10pm on a weekday back then.. It&#x27;s messy but I still stand by everything I said in there.&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;a href=&#x22;https://damien.zone/astro-and-mastodon-instance/&#x22;&#x3E;Running my own Mastodon instance &#x22;behind&#x22; Astro on Vercel&#x3C;/a&#x3E;. Very specific/technical so idk, if you happen to run your own Mastodon/fediverse instance &#x3C;em&#x3E;and&#x3C;/em&#x3E; also have a website hosted on Vercel, maybe you might find this useful? Who knows.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;Cheers,&#x3C;/p&#x3E;
&#x3C;p&#x3E;- damien&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/release-notes-end-of-september-2024&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>hacking together a local CSS editing workflow on bear</title>
          <link href="https://damien.zone/hacking-together-a-local-css-editing-workflow-on-bear" rel="alternate"/>
          <id>https://damien.zone/hacking-together-a-local-css-editing-workflow-on-bear</id>
          <published>2024-09-17T05:38:00Z</published>
          <updated>2024-09-21T08:33:17Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;#now playing: &#x3C;a href=&#x22;https://memorexmemories.bandcamp.com/album/pictures-of-purple-skies&#x22;&#x3E;Pictures of Purple Skies by Memorex Memories&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;I have been enjoying the &#x22;no frills&#x22; aspect of running a blog on bear so far. the one thing I am missing from my previous blog setup, however, is a way to quickly experiment with the CSS of my blog.&#x3C;/p&#x3E;
&#x3C;p&#x3E;while bear&#x27;s dashboard has been pretty convenient to quickly edit some CSS variables, I feel if I want to do deeper edits the &#x22;tweak -&#x26;gt; publish -&#x26;gt; refresh&#x22; loop will feel like a slow to me.&#x3C;/p&#x3E;
&#x3C;p&#x3E;so I did what I usually do in those situations: I write some JavaScript&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E; about it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The code is on &#x3C;a href=&#x22;https://github.com/eramdam/files.damien.zone&#x22;&#x3E;https://github.com/eramdam/files.damien.zone&#x3C;/a&#x3E; but the logic is pretty straightforward:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;run a web server running on &#x3C;code&#x3E;localhost:3000&#x3C;/code&#x3E; (I&#x27;m using fastify but i&#x27;m sure any web server thing for Node would work)&#x3C;/li&#x3E;
&#x3C;li&#x3E;run an instance of &#x3C;a href=&#x22;https://github.com/tapio/live-server&#x22;&#x3E;live-server&#x3C;/a&#x3E; in parallel (this one is key!)&#x3C;/li&#x3E;
&#x3C;li&#x3E;on every route, take the request&#x27;s URL, transform the URL such that &#x3C;code&#x3E;localhost:3000/foobar&#x3C;/code&#x3E; becomes &#x3C;code&#x3E;damien.zone/foobar&#x3C;/code&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;download the HTML from &#x3C;code&#x3E;damien.zone/foobar&#x3C;/code&#x3E;, parse it, remove every stylesheets from it, and inject my own from the repo&#x3C;/li&#x3E;
&#x3C;li&#x3E;and lastly, inject a modified version of the &#x3C;a href=&#x22;https://github.com/tapio/live-server/blob/master/injected.html&#x22;&#x3E;injected.html file&#x3C;/a&#x3E; from the &#x3C;a href=&#x22;https://github.com/tapio/live-server/&#x22;&#x3E;live-server&#x3C;/a&#x3E; repo, which will make the live reloading of stylesheets work&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;then the whole thing runs with a simple &#x3C;code&#x3E;npm run start&#x3C;/code&#x3E;, I open &#x3C;code&#x3E;localhost:3000&#x3C;/code&#x3E; in my browser and.. it just works! I can edit my CSS freely and with instant feedback.&#x3C;/p&#x3E;
&#x3C;p&#x3E;it feels like a very stupid solution but as I often like to say: &#x22;If it&#x27;s stupid and it works, it&#x27;s not stupid&#x22;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;see ya,&#x3C;br /&#x3E;
- damien&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;or rather, TypeScript these days, I&#x27;m not a fool &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/hacking-together-a-local-css-editing-workflow-on-bear&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>what to expect on damien dot zone</title>
          <link href="https://damien.zone/what-to-expect-on-damienzone" rel="alternate"/>
          <id>https://damien.zone/what-to-expect-on-damienzone</id>
          <published>2024-09-16T05:24:00Z</published>
          <updated>2024-09-21T08:34:28Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;#now playing: &#x3C;a href=&#x22;https://album.link/us/i/1739079974&#x22;&#x3E;BRAT by Charli XCX&#x3C;/a&#x3E;_&#x3C;/p&#x3E;
&#x3C;p&#x3E;the past weekend, like the past week before it, has seen me go through a whole gamut of emotions.&#x3C;/p&#x3E;
&#x3C;p&#x3E;the good, the bad, and everything in between, I feel I&#x27;ve gone through it all.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I keep telling myself that I feel very goofy for reacting so strongly about losing a &#x3C;em&#x3E;website&#x3C;/em&#x3E;, and... I do still feel that way, but in the second part of the week, I realized that what I&#x27;m reacting to is losing the people I&#x27;ve interacted with, read and met on cohost. a space that truly felt special.&#x3C;/p&#x3E;
&#x3C;p&#x3E;like I said in my &#x3C;a href=&#x22;/hello-internet-again/&#x22;&#x3E;previous article&#x3C;/a&#x3E;, cohost made me realize that I could just... do my little posts, be myself, cringe, sometimes annoying, loud, vocal about my interests and people would show up.&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;I think it will warrant a whole section of the article I will write about my &#x22;story with cohost&#x22; and online in general but I&#x27;ve come to realize that microblogging really, really isn&#x27;t for me any more dude. or at the very least, not the version of it that Twitter&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-2&#x22; id=&#x22;user-content-fnref-2&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;2&#x3C;/a&#x3E;&#x3C;/sup&#x3E; presents as the &#x22;default&#x22;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;for all its issues&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-3&#x22; id=&#x22;user-content-fnref-3&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;3&#x3C;/a&#x3E;&#x3C;/sup&#x3E;, Mastodon has always felt like a &#x22;quieter Twitter&#x22;. but it still had Numbers&#x2122;&#xFE0F; and was still very much trying to emulate Twitter, despite what its creator might say. so I will definitely keep using it. the fact that I&#x27;m now running my own instance is also helping me feel like I have more control over it. but it will be for the &#x22;I ate an apple today, it was very juicy&#x22; type posts.&#x3C;/p&#x3E;
&#x3C;p&#x3E;for everything else, I had cohost, and now I have damien.zone.&#x3C;/p&#x3E;
&#x3C;p&#x3E;at any rate! the &#x22;goals&#x22; or at least &#x22;guidelines&#x22; I want to set for myself in this space are:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;be cringe, be free&#x3C;/li&#x3E;
&#x3C;li&#x3E;don&#x27;t worry too much about it. what are you gonna do if you don&#x27;t like what you&#x27;re seeing? not read it? big whoop.&#x3C;/li&#x3E;
&#x3C;li&#x3E;tinker and have fun with it&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;Those past few days I have seen a bunch of my online friends and acquaintances mess around with their online presence. make blogs on Bear (that this blog runs on!), and just have fun with it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;and I am excited to try this...for the first time? Despite being old enough (I think) to have known that era, I never actually experienced the &#x22;geocities and myspace&#x22; era of the Internet firsthand. and I think by the time &#x3C;a href=&#x22;https://neocities.org/&#x22;&#x3E;neocities&#x3C;/a&#x3E; became a thing I was already tech-savvy enough to feel like it was a &#x22;baby&#x27;s first website&#x22; tool, and I was A Big Boy Programmer who could do all of that shit himself.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I was maybe a bit right, but what good did that do me if I never made anything out of it? so despite it being more &#x22;limited&#x22; than what I had &#x3C;a href=&#x22;https://erambert.me/&#x22;&#x3E;before&#x3C;/a&#x3E;, Bear really feels &#x22;small but mighty&#x22; in a very liberating way.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I am very excited about doing stuff I never got to do and that are coming back in fashion like buttons, have my site be on a webring, show off blogs I like in a blogroll. I am excited about maybe making a &#x3C;a href=&#x22;https://sive.rs/nowff&#x22;&#x3E;&#x22;now&#x22; page&#x3C;/a&#x3E; for myself, tinkering with the theme of this blog.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I know myself and there is a real chance I might do &#x22;too much too quickly&#x22; and burn myself out, but so far, Bear&#x27;s defaults have been &#x22;sane&#x22; enough to only warrant tiny tweaks.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I don&#x27;t want to worry about everything being perfect, clean, right, or any combination of all three anymore.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I just want my little space to make my little website and write my little posts on it. It feels both very nostalgic and new at the same time, and I think I will like it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;love you,&#x3C;/p&#x3E;
&#x3C;p&#x3E;- damien&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;assuming you use the tools the site gives you in order to be &#x22;discovered&#x22; (which you might think would be a low bar and yet) &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-2&#x22;&#x3E;
&#x3C;p&#x3E;and Bluesky, sorry not sorry if you&#x27;re coming from there lol &#x3C;a href=&#x22;#user-content-fnref-2&#x22; data-footnote-backref aria-label=&#x22;Back to reference 2&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-3&#x22;&#x3E;
&#x3C;p&#x3E;and trust me I &#x3C;em&#x3E;know&#x3C;/em&#x3E; about those issues. more on that in a later blog post &#x3C;a href=&#x22;#user-content-fnref-3&#x22; data-footnote-backref aria-label=&#x22;Back to reference 3&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/what-to-expect-on-damienzone&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>hello internet (again)</title>
          <link href="https://damien.zone/hello-internet-again" rel="alternate"/>
          <id>https://damien.zone/hello-internet-again</id>
          <published>2024-09-15T18:03:00Z</published>
          <updated>2024-09-16T04:45:35Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;So. &#x3C;a href=&#x22;https://cohost.org/staff/post/7611443-cohost-to-shut-down&#x22;&#x3E;cohost&#x3C;/a&#x3E;, huh?&#x3C;/p&#x3E;
&#x3C;p&#x3E;If you&#x27;re reading this, you probably know me from that place (or at least have heard about it) so I don&#x27;t think it&#x27;s really useful to try to give you the &#x22;elevator pitch&#x22;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;what would a pitch be useful for anyway, right?&#x3C;/p&#x3E;
&#x3C;p&#x3E;I have &#x3C;em&#x3E;a lot&#x3C;/em&#x3E; I want to say about cohost. but I think the shutdown announcement is still too recent for me to be able to form any coherent thoughts yet.&#x3C;/p&#x3E;
&#x3C;p&#x3E;the one thing that I will say about cohost is that it, as a site and &#x22;community&#x22;&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-2&#x22; id=&#x22;user-content-fnref-2&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;, taught me that I can &#x22;exist online&#x22;&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;2&#x3C;/a&#x3E;&#x3C;/sup&#x3E; without worrying about being &#x22;clean&#x22; or &#x22;proper&#x22; or &#x22;right&#x22;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;most of my existence online was on micro-blogging platforms with short character limits and a high incentive to product the &#x22;One Good Take&#x22; about everything and anything. and I&#x27;m frankly done with that.&#x3C;/p&#x3E;
&#x3C;p&#x3E;or at least I&#x27;m done with it being my only outlet for Thoughts online. and I have cohost to thank for for letting me experiment and find this out about myself.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I already have a &#x3C;a href=&#x22;https://erambert.me/&#x22;&#x3E;website&#x3C;/a&#x3E; that I was planning on using as my new place for long/medium form writing but after trying (and failing) to get anything written there I came to a conclusion. my friend evie is right in that &#x3C;a href=&#x22;https://cohost.org/ewie/post/7707570-guys-who-are-moving&#x22;&#x3E;&#x22;you gotta make it easy to post&#x22;&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;as far as I can tell bearblog seems to strike a right balance between making it easy and letting me tinker with things while not letting me fall into what some might call &#x22;the developer&#x27;s blog curse&#x22;. so here I am.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://erambert.me&#x22;&#x3E;erambert.me&#x3C;/a&#x3E; will still exist as &#x22;the website I give by default&#x22; both because I like the separation of &#x22;concerns&#x22; (&#x27;business card type site&#x27; versus &#x27;just me writing&#x27;) and also because &#x3C;em&#x3E;so much&#x3C;/em&#x3E; is tied to this domain that I refuse to mess with it.
anyway!&#x3C;/p&#x3E;
&#x3C;p&#x3E;this is &#x3C;a href=&#x22;https://damien.zone&#x22;&#x3E;damien.zone&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I&#x27;m nervous, I&#x27;m sad, I have thoughts, I&#x27;m excited to try this. let&#x27;s go and post about it like it&#x27;s 2007 again.&#x3C;/p&#x3E;
&#x3C;p&#x3E;pardon the mess, appreciate you &#x26;lt;3&#x3C;/p&#x3E;
&#x3C;p&#x3E;- damien&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-2&#x22;&#x3E;
&#x3C;p&#x3E;I don&#x27;t like saying social media sites have &#x22;a community&#x22; because there&#x27;s so many people on them but &#x3C;em&#x3E;I&#x3C;/em&#x3E; definitely had something I would call a community on cohost &#x3C;a href=&#x22;#user-content-fnref-2&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;whatever that means &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 2&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/hello-internet-again&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Running my own Mastodon instance &#x22;behind&#x22; Astro on Vercel</title>
          <link href="https://damien.zone/astro-and-mastodon-instance" rel="alternate"/>
          <id>https://damien.zone/astro-and-mastodon-instance</id>
          <published>2024-08-11T07:00:00Z</published>
          <updated>2024-11-02T03:15:47Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;picture&#x3E;
  &#x3C;source srcset=&#x22;https://damien.zone/img/blog/mastodon-dark.png&#x22; media=&#x22;(prefers-color-scheme: dark)&#x22; type=&#x22;image/png&#x22;&#x3E;&#x3C;/source&#x3E;
  &#x3C;source srcset=&#x22;https://damien.zone/img/blog/mastodon-light.png&#x22; type=&#x22;image/png&#x22;&#x3E;&#x3C;/source&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/mastodon-light.png&#x22; alt=&#x22;My profile on my Mastodon instance&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; /&#x3E;
&#x3C;/picture&#x3E;
&#x3C;p&#x3E;The Mastodon instance I&#x27;ve been on for the past 7 years, &#x3C;a href=&#x22;https://octodon.social&#x22;&#x3E;octodon.social&#x3C;/a&#x3E; is &#x3C;a href=&#x22;https://octodon.social/@CobaltVelvet/112897672123037837&#x22;&#x3E;shutting down next year&#x3C;/a&#x3E;. So rather than try to find a replacement, I decided to run my own, single-user instance.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The issue isn&#x27;t that good, well-moderated instances don&#x27;t exist, they do! But one of the big reasons why I stayed on Octodon was because I knew the moderation team personally so I trusted their decisions and agreed with most of them. I just frankly couldn&#x27;t be bothered with having to find and vet a new instance and I like to tinker so, after some advices from my friend &#x3C;a href=&#x22;https://nileane.fr/&#x22;&#x3E;Nil&#xE9;ane&#x3C;/a&#x3E; I went and spun up my own!&#x3C;/p&#x3E;
&#x3C;p&#x3E;It&#x27;s up at &#x3C;a href=&#x22;https://social.erambert.me&#x22;&#x3E;https://social.erambert.me&#x3C;/a&#x3E; and you can find me on Mastodon by looking up &#x3C;code&#x3E;@eramdam@erambert.me&#x3C;/code&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The setup isn&#x27;t anything too fancy:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;a dedicated server hosted by &#x3C;a href=&#x22;https://eco.ovhcloud.com/en/&#x22;&#x3E;OVH&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;OVH&#x27;s &#x3C;a href=&#x22;https://us.ovhcloud.com/public-cloud/object-storage/&#x22;&#x3E;object storage solution&#x3C;/a&#x3E; for media files behind &#x3C;a href=&#x22;https://bunny.net/&#x22;&#x3E;Bunny&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;running Mastodon 4.2.10 (current stable version at the time of writing)&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;All set up while following the &#x3C;a href=&#x22;https://docs.joinmastodon.org/admin/prerequisites/&#x22;&#x3E;official documentation&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The only quirk of my setup might is that the &#x22;local domain&#x22; (domain the instance responds to) and the &#x22;web domain&#x22; (domain where the Web interface lives) are different. Meaning that people can find me by looking up @&#x3C;a href=&#x22;mailto:eramdam@erambert.me&#x22;&#x3E;eramdam@erambert.me&#x3C;/a&#x3E; despite the actual instance running on &#x3C;a href=&#x22;https://social.erambert.me&#x22;&#x3E;https://social.erambert.me&#x3C;/a&#x3E;. It&#x27;s a behavior that is &#x3C;a href=&#x22;https://docs.joinmastodon.org/admin/config/#web_domain&#x22;&#x3E;well documented&#x3C;/a&#x3E; by Mastodon and is usually trivial to implement when you host your website on your own server...&#x3C;/p&#x3E;
&#x3C;p&#x3E;Except I don&#x27;t do that &#x1F605; My website is, for now, running on &#x3C;a href=&#x22;https://astro.build&#x22;&#x3E;Astro&#x3C;/a&#x3E; and hosted on &#x3C;a href=&#x22;https://vercel.com/&#x22;&#x3E;Vercel&#x3C;/a&#x3E; so I can&#x27;t just modify the web server configuration to set up the necessary redirection.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Now, I&#x27;m not the only one that tried to do this with a similar setuip &#x3C;a href=&#x22;https://www.danillouz.dev/posts/mastodon-alias#using-my-custom-domain-as-an-alias&#x22;&#x3E;link&#x3C;/a&#x3E; &#x3C;a href=&#x22;https://brandonrozek.com/blog/mastodon-webfinger-alias-using-redirects/&#x22;&#x3E;link&#x3C;/a&#x3E; &#x3C;a href=&#x22;https://www.seanmcp.com/articles/use-your-domain-on-mastodon-with-astro/&#x22;&#x3E;link&#x3C;/a&#x3E;. But none of those solutions were satisfactory for me because:&#x3C;/p&#x3E;
&#x3C;ol&#x3E;
&#x3C;li&#x3E;they assume only &#x3C;em&#x3E;one&#x3C;/em&#x3E; account as the &#x22;destination&#x22; OR&#x3C;/li&#x3E;
&#x3C;li&#x3E;they work by outputing a &#x22;dumb&#x22; JSON file.&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;p&#x3E;I want to have the options to maybe host more than one account on my instance so those limitations were deal-breaker. Thankfully &#x3C;a href=&#x22;https://www.seanmcp.com/articles/use-your-domain-on-mastodon-with-astro/&#x22;&#x3E;Sean McPherson&#x27;s&#x3C;/a&#x3E; article put me on the right track and I ended up implementing an &#x3C;a href=&#x22;https://docs.astro.build/en/guides/endpoints/&#x22;&#x3E;Astro endpoint&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;All I had to was write this in a file under &#x3C;code&#x3E;src/pages/.well-known/webfinger.ts&#x3C;/code&#x3E;, make sure my site was using the &#x3C;a href=&#x22;https://docs.astro.build/en/guides/integrations-guide/vercel/&#x22;&#x3E;Vercel adapter&#x3C;/a&#x3E; to run in server mode instead of static mode and I was done!&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame has-title&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;span class=&#x22;title&#x22;&#x3E;src/pages/.well-known/webfinger.ts&#x3C;/span&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;typescript&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { APIRoute } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;astro&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;destinationInstance&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://social.erambert.me&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;export&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;GET&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;APIRoute&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;async&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; ({ &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;request&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; }) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;url&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;URL&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(request.url);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;newUrl&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;URL&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;url.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toString&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;().&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;replace&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(url.origin, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;destinationInstance,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;response&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;fetch&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(newUrl.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toString&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;());&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;json&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;await&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; response.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;json&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;();&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;Response&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;JSON&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;stringify&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(json, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;null&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;2&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;), {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;headers: {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;Content-Type&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;application/jrd+json&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;Access-Control-Allow-Origin&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;*&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;},&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;});&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;};&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;Now people could query &#x3C;code&#x3E;@eramdam@erambert.me&#x3C;/code&#x3E; and find me as if they queried &#x3C;code&#x3E;@eramdam@social.erambert.me&#x3C;/code&#x3E;! Neat!&#x3C;/p&#x3E;
&#x3C;p&#x3E;After having written this post, &#x3C;a href=&#x22;https://mastodon.guerilla.studio/@tixie&#x22;&#x3E;Tixie&#x3C;/a&#x3E; made me realize that I &#x3C;em&#x3E;could&#x3C;/em&#x3E; use Astro&#x27;s &#x3C;code&#x3E;redirect&#x3C;/code&#x3E; method instead of doing a fetch in the endpoint code? Both seem to work but I am a bit worried about the potentially missing &#x3C;code&#x3E;Access-Control-Allow-Origin&#x3C;/code&#x3E; header...&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame has-title&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;span class=&#x22;title&#x22;&#x3E;src/pages/.well-known/webfinger.ts&#x3C;/span&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;typescript&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;import&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; { APIRoute } &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;from&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;astro&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;export&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;GET&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;:&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;APIRoute&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;async&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; ({ &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;request&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#FFAB70;--1:#AE4B07&#x22;&#x3E;redirect&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; }) &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x26;gt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; {&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;url&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;URL&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(request.url);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;const&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;newUrl&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;new&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;URL&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;url.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toString&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;().&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;replace&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(url.origin, &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;),&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://social.erambert.me&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;
&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#F97583;--1:#BF3441&#x22;&#x3E;return&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E; &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;redirect&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(newUrl.&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;toString&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;(), &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;301&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;);&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;};&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;Update on September 3rd: It turns out, &#x3C;a href=&#x22;https://vercel.com/docs/edge-network/rewrites&#x22;&#x3E;Vercel rewrites&#x3C;/a&#x3E; work just fine for this and I didn&#x27;t realize &#x1F604; I added the following file to my repo and I was done&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame has-title&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;span class=&#x22;title&#x22;&#x3E;vercel.json&#x3C;/span&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;json&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;&#x22;rewrites&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: [&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;{&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;&#x22;source&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;/.well-known/webfinger&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;,&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;      &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#79B8FF;--1:#005CC5&#x22;&#x3E;&#x22;destination&#x22;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;: &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://social.erambert.me/.well-known/webfinger&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;    &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;]&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;}&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/astro-and-mastodon-instance&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>The intersection of liberal arts and technology</title>
          <link href="https://damien.zone/intersection-of-liberal-arts-and-technology" rel="alternate"/>
          <id>https://damien.zone/intersection-of-liberal-arts-and-technology</id>
          <published>2024-03-27T07:00:00Z</published>
          <updated>2024-09-21T08:44:02Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;&#x3C;small&#x3E;Inspired by &#x3C;a href=&#x22;https://lmnt.me/blog/lack-of-vision.html&#x22;&#x3E;&#x22;Lack of Vision&#x22; by Louie Mantia&#x3C;/a&#x3E;.&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;p&#x3E;It&#x2019;s technology married with liberal arts, married with the humanities, that yields us the results that make our heart sing.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;I have been thinking about this quote recently.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I&#x27;ve never really considered myself &#x3C;em&#x3E;an artist&#x3C;/em&#x3E;. Sure, I&#x27;ve spent hours upon hours messing around in Photoshop as a teenager on the family computer, learning &#x3C;em&#x3E;graphic design&#x3C;/em&#x3E; by following tutorials written by other amateurs. Does that make me an artist? I don&#x27;t know.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I&#x27;ve always been more into what we&#x27;d call web design and UI design. I&#x27;ve learned the ropes of all of this by just fiddling with existing things. It might feel &#x22;pointless&#x22; to an outsider, but I remember taking great joy in essentially doing &#x22;vector tracing&#x22; with Photoshop&#x27;s Pen tool over various pictures of my favorite fictional characters, pieces of tech and such.&#x3C;/p&#x3E;
&#x3C;p&#x3E;All in service of figuring &#x3C;em&#x3E;how&#x3C;/em&#x3E; to reproduce that &#x3C;em&#x3E;one&#x3C;/em&#x3E; gradient, that &#x3C;em&#x3E;one&#x3C;/em&#x3E; visual effect, etc. I distinctly remember doing that over a (I didn&#x27;t know it was at the time) render of &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Apple_Cinema_Display?useskin=vector&#x22;&#x3E;Apple&#x27;s iconic Cinema Display&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;For fun, I was messing around.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Around 2009 or so, I got my first iMac (the first aluminum one). I had been lusting for this computer for a long time before my parents got it as a birthday present. I browsed Apple&#x27;s website, enamored by the design of the hardware &#x3C;em&#x3E;and&#x3C;/em&#x3E; the software.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I was so enamored by the visual, dare I say artistic, quality of the software (I couldn&#x27;t judge anything else by that point) that I had gotten into the hobby of disguising my Windows XP installation into Mac OS X &#x22;Tiger&#x22; and later on, Mac OS X &#x22;Leopard&#x22;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Even after getting my Mac, I didn&#x27;t stop obsessing over that aspect of my computing life. I took any excuse I could to change my system or Dock icons by downloading a pack from &#x3C;a href=&#x22;https://iconfactory.com/&#x22;&#x3E;The Iconfactory&#x3C;/a&#x3E;, MacThemes.net or DeviantArt.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Later on, I would take an interest in web design. At this point (late 2000s), web design really was &#x3C;a href=&#x22;https://www.instagram.com/webdesignmuseum/&#x22;&#x3E;&#x3C;em&#x3E;unique&#x3C;/em&#x3E;&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Since I didn&#x27;t have any technical knowledge, I was &#x22;only&#x22; designing. I remember growing frustrated when my one developer friend would take too long to implement something. But it was gratifying to see the things I &#x22;drew&#x22; become alive and interactive.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Over time, I took it upon myself to learn HTML, CSS, and everything else. This was around the time when a little thing called &#x3C;a href=&#x22;https://wordpress.org/&#x22;&#x3E;WordPress&#x3C;/a&#x3E; was the hot new thing on the block.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I didn&#x27;t have much of an &#x22;education&#x22; with these things. I would learn by breaking things. Not only that, but I would take an existing blog theme, tweak a few lines of CSS there a few HTML blocks here, and see what happens. And repeat, and repeat, and repeat.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Later, a friend and I teamed up to do more &#x22;web design&#x22; work, not in any official capacity (we were still students) but as a hobby. I was still design-oriented, had opinions and would draw web designs, but he was always the one who would come up with crazy visual ideas that browsers of the time wouldn&#x27;t be capable of reproducing accurately until 15 years later.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Coming up with &#x3C;em&#x3E;a way&#x3C;/em&#x3E; to convey the effect &#x3C;em&#x3E;somehow&#x3C;/em&#x3E; was gratifying. It may sound corny, but I felt like an illusionist! An illusionist who made you believe that Safari or Firefox in 2010 could show you some crazy background with rounded corners and shadows.&#x3C;/p&#x3E;
&#x3C;p&#x3E;As time passed, I honed my skills, learned, and did more web design work for clients while I was studying.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I would then get a job at my current &#x3C;a href=&#x22;https://front.com/&#x22;&#x3E;workplace&#x3C;/a&#x3E; as the first front-end developer, or &#x22;the CSS guy,&#x22; as the CTO would say back then.&#x3C;/p&#x3E;
&#x3C;p&#x3E;This was in 2014. Browsers had gotten better, but progress was still slow. Showing vector icons on a web page was a &#x3C;em&#x3E;new technique&#x3C;/em&#x3E;. We used fonts with icons because it was the only &#x22;reliable&#x22; way of showing vector graphics! It was terrible for various reasons, but also awesome; we were tricking the machine into doing what we wanted.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I&#x27;ll always fondly remember the arguments I would have with &#x3C;a href=&#x22;http://areskub.com/&#x22;&#x3E;our designer&#x3C;/a&#x3E; at the time. I had to be &#x22;that guy,&#x22; explaining that, sadly, that cool-looking UI effect wasn&#x27;t possible or not practically and then coming up with a way to make it work even if it is far from perfect. But yet, it felt magical.&#x3C;/p&#x3E;
&#x3C;hr /&#x3E;
&#x3C;p&#x3E;Ten years later?&#x3C;/p&#x3E;
&#x3C;p&#x3E;I think we lost it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Art and technology don&#x27;t intersect anymore.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Tech sees Art as a liability. Not being an artist or a designer is now something that needs fixing, something that &#x3C;em&#x3E;you&#x3C;/em&#x3E; can solve by buying &#x3C;a href=&#x22;https://www.canva.com/&#x22;&#x3E;someone&#x3C;/a&#x3E; &#x3C;a href=&#x22;https://openai.com/dall-e-2&#x22;&#x3E;else&#x27;s&#x3C;/a&#x3E; &#x3C;a href=&#x22;https://openai.com/sora&#x22;&#x3E;product&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Art is a resource to be mined; art is an &#x3C;a href=&#x22;https://www.youtube.com/watch?v=YQ_xWvX1n9g&#x22;&#x3E;asset&#x3C;/a&#x3E; and cannot exist on its own anymore.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The &#x3C;em&#x3E;act&#x3C;/em&#x3E; of making art, what makes art valuable as part of the human experience, is an inefficiency that needs to be optimized for some fucking reason.&#x3C;/p&#x3E;
&#x3C;p&#x3E;This sucks and makes my heart boil.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I don&#x27;t know how to fix it, I just know we lost the plot, and it makes me sad.&#x3C;/p&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/intersection-of-liberal-arts-and-technology&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Better TweetDeck, a Post-Mortem, Part 2: A written history and credits</title>
          <link href="https://damien.zone/bettertweetdeck-post-mortem-part-2" rel="alternate"/>
          <id>https://damien.zone/bettertweetdeck-post-mortem-part-2</id>
          <published>2024-01-29T08:00:00Z</published>
          <updated>2024-12-07T04:55:00Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;This post will be the second &#x2014;and last, I think&#x2014; part of my &#x22;Better TweetDeck post-mortem&#x22; series.
In this part, I will try to recount the history of Better TweetDeck as well as shout out people who have helped me with the project. You might learn a thing or two even if you used it for years!&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;a-timeline-of-better-tweetdeck&#x22;&#x3E;A timeline of Better TweetDeck&#x3C;/h2&#x3E;
&#x3C;p&#x3E;As it turns out, trying to recall and tell 9 years of history of a project without prior notes is kinda hard! Who knew! And I think most of it would be boring, as the bulk of my changelogs aren&#x27;t particularly interesting. So, rather than go through every single release, I will try to do a &#x22;best highlights&#x22; retelling of what the project went through. If you want to follow along, I have put together a copy of the full changelog of (almost) every tagged version of Better TweetDeck &#x3C;a href=&#x22;/btd/btd-changelog&#x22;&#x3E;right here&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;a-bunch-of-js-and-css-put-together&#x22;&#x3E;A bunch of JS and CSS put together&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;December 2013&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;I was a student at the time, finishing up my last year of university, living at my parents&#x27; place. Unfortunately, we lived in the countryside and that mean we had a &#x3C;em&#x3E;terribly&#x3C;/em&#x3E; slow internet connection. I&#x27;m talking less than 1Mbps slow. It wasn&#x27;t great! But it was manageable.&#x3C;/p&#x3E;
&#x3C;p&#x3E;While I can&#x27;t remember what prompted me to start using TweetDeck specifically (this was after the acquisition by Twitter). I do remember being extremely annoyed at having to wait for &#x3C;a href=&#x22;https://t.co&#x22;&#x3E;t.co&#x3C;/a&#x3E; (Twitter&#x27;s URL shortener) when clicking on. Every. Single. Link. Somehow, this domain is still the slowest domain I regularly encounter, and it was slow at the time already!&#x3C;/p&#x3E;
&#x3C;p&#x3E;At that point, I had been learning web development for a few years, which made me think that &#x3C;em&#x3E;surely&#x3C;/em&#x3E; there was a way to fix this with a userscript or browser extension, right? So I opened up my Chrome developer tools, looked around on my feed, and would you look at that!&#x3C;/p&#x3E;
&#x3C;div class=&#x22;expressive-code&#x22;&#x3E;&#x3C;figure class=&#x22;frame&#x22;&#x3E;&#x3C;figcaption class=&#x22;header&#x22;&#x3E;&#x3C;/figcaption&#x3E;&#x3C;pre data-language=&#x22;html&#x22;&#x3E;&#x3C;code&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;lt;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;a&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;href&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://t.co/1234&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;target&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;_blank&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;class&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;url-ext&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line highlight mark&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#c2a8f3;--1:#613aa9&#x22;&#x3E;data-full-url&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://google.com&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;rel&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;url noopener noreferrer&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#B392F0;--1:#6F42C1&#x22;&#x3E;title&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;=&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#9ECBFF;--1:#032F62&#x22;&#x3E;&#x22;https://google.com&#x22;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span class=&#x22;indent&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;  &#x3C;/span&#x3E;&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;google.com&#x26;lt;/&#x3C;/span&#x3E;&#x3C;span style=&#x22;--0:#85E89D;--1:#1E7734&#x22;&#x3E;a&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;ec-line&#x22;&#x3E;&#x3C;div class=&#x22;code&#x22;&#x3E;&#x3C;span style=&#x22;--0:#E1E4E8;--1:#24292E&#x22;&#x3E;&#x26;gt;&#x3C;/span&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/code&#x3E;&#x3C;/pre&#x3E;&#x3C;div class=&#x22;copy&#x22;&#x3E;&#x3C;div aria-live=&#x22;polite&#x22;&#x3E;&#x3C;/div&#x3E;&#x3C;div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/figure&#x3E;&#x3C;/div&#x3E;
&#x3C;p&#x3E;&#x3C;code&#x3E;data-full-url&#x3C;/code&#x3E;! That&#x27;s what I wanted! So off I went, putting together a first version of Better TweetDeck that added a &#x22;t.co removal&#x22; feature, alongside a few others, in &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commit/a5e002f1&#x22;&#x3E;January 2014&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The extension wasn&#x27;t public at this point: it didn&#x27;t even have an icon or anything. But a few friends of mine were testing it to provide feedback (and make sure I didn&#x27;t break anything in a catastrophic way).&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-3&#x22; id=&#x22;user-content-fnref-3&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;1st-public-release&#x22;&#x3E;1st public release&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;29 January 2014&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;On January 29th 2014, I released the first version of Better TweetDeck to the public. Funnily enough, it was &#x3C;em&#x3E;not&#x3C;/em&#x3E; 1.0.0 but 0.0.7 &#x1F605;&#x3C;/p&#x3E;
&#x3C;p&#x3E;It had the following features (taken from the &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/blob/4bb210d4be6cc14843ded5f590859126789974df/README.md&#x22;&#x3E;README file&#x3C;/a&#x3E;):&#x3C;/p&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;Thumbnails for Imgur and Droplr images links&#x3C;/li&#x3E;
&#x3C;li&#x3E;Allow to change the time formatting (Relative or Absolute)&#x3C;/li&#x3E;
&#x3C;li&#x3E;Allow to change the username/full name formatting (Username only, Full name only, both or inverted (Username Full name))&#x3C;/li&#x3E;
&#x3C;li&#x3E;Display fancy circled avatars (they&#x27;re hipsters, but they&#x27;re cute too!)&#x3C;/li&#x3E;
&#x3C;li&#x3E;Remove that god-damn useless t.co redirection on links&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;I used to swear a bit (too much) when writing code&#x3C;/small&#x3E;&#x3C;br /&#x3E;
And here it is running on modern Chrome on modern macOS &#x1F604;&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/btd-post-mortem2/btd-0.0.8.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-0.0.8.jpg&#x22; alt=&#x22;The first public version of Better TweetDeck running in Chrome on macOS in 2023&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;The first public version of Better TweetDeck running in Chrome on macOS in 2023&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;hitting-10&#x22;&#x3E;Hitting 1.0&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;February 2014&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;A month later, Better TweetDeck hit 1.0! Yay! It now had a proper &#x22;welcome&#x22; screen banner and a &#x3C;a href=&#x22;/btd/btd-changelog#100&#x22;&#x3E;bunch of new features&#x3C;/a&#x3E;. Most of them were tweaks and improvements of existing features, but the biggest part of that changelog was the addition of more &#x22;providers&#x22; for the thumbnails feature, which made it so links from websites with not-so-great Open Graph support could look nicer and have more functionality inside TweetDeck. I would love to show how it looked back then, but I couldn&#x27;t find a screenshot of that specific feature running on that specific version of TweetDeck &#x1F643;. So, instead, enjoy a &#x3C;a href=&#x22;/img/blog/btd-post-mortem2/btd-1.0.0.png&#x22;&#x3E;screenshot of the options page in modern Chrome&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The extension&#x27;s user base was tiny at the time (around 200 weekly users), but it was fine by me. I was making this for myself &#x3C;em&#x3E;first&#x3C;/em&#x3E; and for others second. It was mostly spreading through word of mouth at that point.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;a-twist&#x22;&#x3E;A twist?!&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;February - April 2014&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;But little did I know, the TweetDeck team had noticed it despite its small reach. That&#x27;s when I got an email from &#x3C;a href=&#x22;https://twitter.com/jamesbroadhead&#x22;&#x3E;James Broadhead&#x3C;/a&#x3E;, suggesting that I apply for a summer internship at Twitter UK in London!&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/btd-post-mortem2/btd-email-james.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-email-james.png&#x22; alt=&#x22;&#x26;quot;Hi Damien! I&#x27;m a Software Engineer on the TweetDeck team. We came across Better TweetDeck, which I&#x27;ve used for the past day or so -- you&#x27;ve got some really neat ideas in there. I wonder if you&#x27;d be interested in coming to London for the summer as an intern to work on TweetDeck? The title says &#x27;Software Engineer&#x27;, but if you&#x27;re interested in working closely with our design team on UI/UX work, I&#x27;m sure that we can arrange that. It&#x27;s a paid position, which should cover a summer in the UK :) Although we don&#x27;t have any full-time roles advertised at the moment, getting a position after a good internship should be easy to arrange, if you&#x27;re interested. I&#x27;m not a recruiter, but if you&#x27;re interested, I can pass your details along  (or just apply through the site directly). All the best - James Broadhead&#x26;quot;&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;&#x22;Hi Damien! I&#x27;m a Software Engineer on the TweetDeck team. We came across Better TweetDeck, which I&#x27;ve used for the past day or so -- you&#x27;ve got some really neat ideas in there. I wonder if you&#x27;d be interested in coming to London for the summer as an intern to work on TweetDeck? The title says &#x27;Software Engineer&#x27;, but if you&#x27;re interested in working closely with our design team on UI/UX work, I&#x27;m sure that we can arrange that. It&#x27;s a paid position, which should cover a summer in the UK :) Although we don&#x27;t have any full-time roles advertised at the moment, getting a position after a good internship should be easy to arrange, if you&#x27;re interested. I&#x27;m not a recruiter, but if you&#x27;re interested, I can pass your details along  (or just apply through the site directly). All the best - James Broadhead&#x22;&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Thus began a months-long application process for this internship. I remember having maybe half a dozen interviews with various Twitter employees trying to gauge my front-end dev skills at the time. Even though I didn&#x27;t get the spot in the end, it was incredibly flattering and enriching to go through the process. I genuinely couldn&#x27;t believe folks at Twitter found my dinky little extension useful! It was completely wild to me.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;emoji&#x22;&#x3E;Emoji!&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;1.4.0, April 2014&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;The project cruised along. I was pushing updates regularly, working on it on my spare time. One of the big features I was proud of was the support of emoji in 1.4.0! It may sound silly nowadays but, at the time, support of emoji outside of macOS/iOS was pretty much non-existent and, from my recollection, Twitter was one of the first websites to support them &#x3C;em&#x3E;and&#x3C;/em&#x3E; have their own set of emoji.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Now, if you know about the &#x3C;a href=&#x22;https://github.com/twitter/twemoji/&#x22;&#x3E;Twemoji project&#x3C;/a&#x3E; (RIP), you might also know that Twitter didn&#x27;t open-sourced it until &#x3C;a href=&#x22;https://blog.twitter.com/developer/en_us/a/2014/open-sourcing-twitter-emoji-for-everyone&#x22;&#x3E;November 2014&#x3C;/a&#x3E;, so how did I support emoji before that?&#x3C;/p&#x3E;
&#x3C;p&#x3E;The hard way! Most of the logic lives in this &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/blob/eaf88f4775e74882b1de6c2ba3ff5ea6ed2a6075/source/js/emojiToImage.js&#x22;&#x3E;file&#x3C;/a&#x3E;, and how I got to that implementation is kind of funny in retrospect.
I remember asking around on an IRC channel I&#x27;d hang out on, and a &#x3C;a href=&#x22;https://github.com/Meroje&#x22;&#x3E;friend&#x3C;/a&#x3E; came up with a way to &#x3C;a href=&#x22;https://gist.github.com/Meroje/9994612&#x22;&#x3E;list all the available URLs of Twitter&#x27;s emoji&#x3C;/a&#x3E;. Since the Gist contains a 20,000-line long text file, it will take a while to load, so I&#x27;m embedding a copy of the README file here, which details the process Meroje went through:&#x3C;/p&#x3E;
&#x3C;blockquote&#x3E;
&#x3C;h4 id=&#x22;purpose&#x22;&#x3E;Purpose&#x3C;/h4&#x3E;
&#x3C;p&#x3E;This was used to find all possible URLs of twitter&#x27;s emojis.&#x3C;br /&#x3E;
The list is used for &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck&#x22;&#x3E;BetterTweetDeck&#x3C;/a&#x3E;&#x27;s emojis replacement script.&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;do-it-at-home&#x22;&#x3E;Do it at home&#x3C;/h4&#x3E;
&#x3C;p&#x3E;First we export all characters from &#x3C;code&#x3E;/System/Library/Input Methods/CharacterPalette.app/Contents/Resources/CharacterDB.sqlite3&#x3C;/code&#x3E; (column &#x3C;code&#x3E;uchr&#x3C;/code&#x3E; from table &#x3C;code&#x3E;unihan_dict&#x3C;/code&#x3E;) as CSV (could have used SQLite from Node.js). This file contains all Unicode characters (54072).&#x3C;/p&#x3E;
&#x3C;p&#x3E;Then this CSV is parsed with Node.js, which outputs corresponding URLs.&#x3C;/p&#x3E;
&#x3C;p&#x3E;To find all emojis from there, you &#x3C;em&#x3E;just&#x3C;/em&#x3E; have to test every URL (&#x3C;a href=&#x22;https://gist.github.com/eramdam/dc05745f977f3fa18dd5&#x22;&#x3E;example&#x3C;/a&#x3E;, &#x3C;a href=&#x22;http://stackoverflow.com/a/22379949/1478202&#x22;&#x3E;another, with paralelism&#x3C;/a&#x3E;) (be gentle, use HEAD) to remove those that return 404.&#x3C;/p&#x3E;
&#x3C;/blockquote&#x3E;
&#x3C;p&#x3E;From there, I had a final list of ~620 supported emoji&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-6&#x22; id=&#x22;user-content-fnref-6&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;2&#x3C;/a&#x3E;&#x3C;/sup&#x3E; and went on to replacing any emoji I&#x27;d find in tweets with their respective image file. The implementation was a bit crude but it worked! And, on top of that, it was completely immune to the &#x3C;a href=&#x22;https://www.youtube.com/watch?v=zv0kZKC6GAM&#x22;&#x3E;infamous XSS vulnerability&#x3C;/a&#x3E; TweetDeck ran into when they rolled out their own support of emoji &#x1F604;&#x3C;/p&#x3E;
&#x3C;p&#x3E;After a few days, I had figured out how to inject an emoji picker. It was very &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/blob/40ad2b3585374677782a46888afcf5f16add2796/source/js/usefulFunctions.js/#L121-L173&#x22;&#x3E;basic&#x3C;/a&#x3E;, but it did the job and was useful for anybody who wasn&#x27;t on macOS (at the time it was the only desktop operating system with native emoji support).&#x3C;/p&#x3E;
&#x3C;p&#x3E;Eventually, TweetDeck rolled out a (safe) implementation of emoji support, so I removed mine around May 2014 while keeping the picker. I tried my best, over the years, to keep the list of supported emoji in the picker up to date, and even managed to monkey patch the built-in emoji replacement code to update more often when Twitter couldn&#x27;t be bothered to update TweetDeck more than a few times a year.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;reaching-20&#x22;&#x3E;Reaching 2.0&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;August 2014&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;In August 2014, I released &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/tree/bacede58aaea3e86c44dbd74acc42e41a603f651&#x22;&#x3E;version 2.0&#x3C;/a&#x3E; of Better TweetDeck. It had a lot of features!&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;A translation and complete redesign of the settings&#x3C;/li&#x3E;
&#x3C;li&#x3E;A homemade emoji picker&#x3C;/li&#x3E;
&#x3C;li&#x3E;The ability to display thumbnails from a dozen services like Imgur, Instagram, SoundCloud, etc.
&#x3C;ul&#x3E;
&#x3C;li&#x3E;Some of those thumbnails relied on &#x3C;a href=&#x22;https://embed.ly/&#x22;&#x3E;Embed.ly&#x3C;/a&#x3E;&#x27;s API, which was very convenient, but that convenience came at a cost (more on that later).&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;A &#x22;Share to TweetDeck&#x22; context menu (that couldn&#x27;t be disabled, this came later as an external contribution)&#x3C;/li&#x3E;
&#x3C;li&#x3E;More granular control of the timestamp display&#x3C;/li&#x3E;
&#x3C;li&#x3E;And many more I forget&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;Here are the settings in action, along with their &#x22;dynamic preview&#x22; system I was so proud of at the time!&#x3C;/p&#x3E;
&#x3C;figure data-type=&#x22;video&#x22;&#x3E;
&#x3C;video src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-2.0-settings.mp4&#x22; poster=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-2.0-settings.jpg&#x22; playsinline controls preload=&#x22;none&#x22;&#x3E;&#x3C;/video&#x3E;
&#x3C;figcaption&#x3E;
  The settings from Better TweetDeck 2.0, running on modern Chrome
&#x3C;/figcaption&#x3E;
&#x3C;/figure&#x3E;
&#x3C;p&#x3E;On the technical side it was also quite a big release:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;I had &#x3C;em&#x3E;actual&#x3C;/em&#x3E; tooling instead of three JavaScript files that were ~700 lines long (although I was using some weird &#x3C;a href=&#x22;https://gulpjs.com/&#x22;&#x3E;&#x3C;code&#x3E;gulp&#x3C;/code&#x3E;&#x3C;/a&#x3E; plugin to &#x22;import&#x22; files to and from each other, it still wasn&#x27;t great)&#x3C;/li&#x3E;
&#x3C;li&#x3E;I was using &#x3C;a href=&#x22;https://sass-lang.com/&#x22;&#x3E;Sass&#x3C;/a&#x3E; for styles, which let me get fancier with CSS customizations&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;This might not seem like much, but it meant that it was much easier for &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/graphs/contributors?from=2014-08-03&#x26;amp;to=2017-12-23&#x26;amp;type=c&#x22;&#x3E;external contributors&#x3C;/a&#x3E; to help on the project &#x1F604;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;2x-and-other-things&#x22;&#x3E;2.x and other things&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;August 2014 - 2016&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;I would love to go into lots of details on what I worked on and added to the project in that timespan, but it turns out I wasn&#x27;t very smart and didn&#x27;t write a single changelog between 2.0.0 and 3.0.0 &#x1F643; Let this serve as a cautionary tale for anybody reading this: write changelogs!&#x3C;/p&#x3E;
&#x3C;p&#x3E;What I do remember is that:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;The project gained quite a bit of steam! Going from ~1700 weekly users after 2.0.0&#x27;s release to ~20,000 right before 3.x&#x27;s release!&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-7&#x22; id=&#x22;user-content-fnref-7&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;3&#x3C;/a&#x3E;&#x3C;/sup&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;I started implementing localization for the settings, so people could translate BTD in their own language&#x3C;/li&#x3E;
&#x3C;li&#x3E;and surely other things I&#x27;m forgetting.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;On a personal level, &#x3C;em&#x3E;a lot&#x3C;/em&#x3E; happened during that time!&#x3C;br /&#x3E;
In summer of 2014, I was in the process of getting ready to start my two years at &#x3C;a href=&#x22;https://www.gobelins-school.com/&#x22;&#x3E;Gobelins&#x3C;/a&#x3E; through an apprenticeship program, which meant I had to find a company to sponsor me. On the advice of a &#x3C;a href=&#x22;http://areskub.com/&#x22;&#x3E;friend&#x3C;/a&#x3E;, I approached &#x3C;a href=&#x22;https://www.wikiwand.com/en/EFounders&#x22;&#x3E;eFounders&#x3C;/a&#x3E;, who told me that they liked what they saw on my resume&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-8&#x22; id=&#x22;user-content-fnref-8&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;4&#x3C;/a&#x3E;&#x3C;/sup&#x3E; but only had full-time positions. To which I cheekily replied &#x22;but &#x3C;em&#x3E;what if&#x3C;/em&#x3E; I applied for a full-time position?&#x22;. One thing leading to another, I ran into &#x3C;a href=&#x22;https://github.com/lperrin&#x22;&#x3E;Front&#x27;s CTO&#x3C;/a&#x3E; with whom I had worked on a previous project. Front was looking for a front-end developer, so everything clicked into place.&#x3C;br /&#x3E;
It was definitely a gamble because, if this didn&#x27;t go through, I would have felt pretty silly, but it paid off and, 9 years &#x2014;phew&#x2014; later, I have zero regrets!&#x3C;/p&#x3E;
&#x3C;p&#x3E;The next summer, I followed the team to San Francisco, which was obviously quite the move! I didn&#x27;t get much done on Better TweetDeck in 2015 because, as it turns out, moving all the way across the world keeps you busy for a while!&#x3C;/p&#x3E;
&#x3C;p&#x3E;In December 2015, I created a &#x3C;a href=&#x22;https://twitter.com/BetterTDeck&#x22;&#x3E;Twitter account for the project&#x3C;/a&#x3E;. up until that point I did all support and communication through my personal account, which got old pretty quickly. From that moment on, most BTD-related communication was done there.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I&#x27;m sure I did more on the project itself but again, my past self&#x27;s poor changelog hygiene is costing me, as I can&#x27;t gather anything useful from my Git history. So let&#x27;s move onto the next milestone!&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;episode-3&#x22;&#x3E;Episode 3&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;3.0, August 2016&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;As the title of this section suggests, I released v3 of BTD in August 2016. It was quite a big release! You can see the &#x3C;a href=&#x22;/btd/btd-changelog#300&#x22;&#x3E;full changelog here&#x3C;/a&#x3E; but the highlights were:&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;complete-rewrite&#x22;&#x3E;Complete rewrite&#x3C;/h4&#x3E;
&#x3C;p&#x3E;Once again, I had rewritten the whole codebase and managed to get an even faster and leaner BTD out of it. I had switched from the weird gulp-based tooling to using Webpack and ES6 modules. This may sound funny in 2023 but, at the time, it was a very recent addition to ECMAScript!&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;ability-to-change-hearts-back-to-stars&#x22;&#x3E;Ability to change hearts back to stars.&#x3C;/h4&#x3E;
&#x3C;p&#x3E;Twitter had renamed &#x22;Favorites&#x22; (using a star icon) to &#x22;Likes&#x22; (using a heart icon). I&#x27;m sure some people wrote about it in greater detail, but this caused quite the turmoil among Twitter users, since &#x22;favorite&#x22; had a more &#x22;neutral&#x22; connotation as to why people were using it, whereas &#x22;like&#x22; was very opiniated. So people (and I, at the time) were glad to be able to change the hearts back to stars.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Fun implementation trivia: when Twitter made that change on the main web app, TweetDeck simply added a &#x3C;code&#x3E;heart&#x3C;/code&#x3E; class to the main &#x3C;code&#x3E;&#x26;lt;body&#x26;gt;&#x3C;/code&#x3E; element of TweetDeck, which meant that switching back to stars was as easy as removing that class at runtime &#x1F604; They eventually went with a more permanent solution, and I had to start embedding old PNGs into BTD&#x27;s code, but that was a fun period.&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;a-lot-of-new-thumbnail-providers-supported&#x22;&#x3E;A &#x3C;em&#x3E;lot&#x3C;/em&#x3E; of new thumbnail providers supported&#x3C;/h4&#x3E;
&#x3C;p&#x3E;At this point, I think the project was supporting maybe 15 different providers? I know the list grew even more when contributors started adding their own.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Like I said earlier, those were using &#x3C;a href=&#x22;https://embed.ly/&#x22;&#x3E;Embed.ly&#x3C;/a&#x3E;, which was great because it had a unified API that supported basically every URL under the sun and could extract a useful thumbnail/embed out of it. Problem was that, despite Embed.ly giving a &#x22;free quota&#x22;&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-9&#x22; id=&#x22;user-content-fnref-9&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;5&#x3C;/a&#x3E;&#x3C;/sup&#x3E;, I blew through it in a matter of &#x3C;em&#x3E;days&#x3C;/em&#x3E; after the release of v3.&#x3C;br /&#x3E;
This meant that I &#x3C;a href=&#x22;https://twitter.com/BetterTDeck/status/762319703419125761&#x22;&#x3E;suddenly owed Embed.ly around ~200$&#x3C;/a&#x3E; after only a week or two, which was not money I could afford to spend on BTD, especially since it didn&#x27;t make any significant income&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-10&#x22; id=&#x22;user-content-fnref-10&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;6&#x3C;/a&#x3E;&#x3C;/sup&#x3E;. I &#x3C;a href=&#x22;https://twitter.com/BetterTDeck/status/762320997429055488&#x22;&#x3E;called for donations/Patreon subscriptions at the time&#x3C;/a&#x3E; but quickly pulled the plug when I realized the juice wasn&#x27;t worth the squeeze.&#x3C;br /&#x3E;
In retrospect, that was the right call since Twitter ended up implementing their &#x3C;a href=&#x22;https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards&#x22;&#x3E;cards&#x3C;/a&#x3E; universally and supporting those in TweetDeck was a better/easier way to go.&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;verified-badges-in-columns&#x22;&#x3E;Verified badges in columns&#x3C;/h4&#x3E;
&#x3C;p&#x3E;This might seem like a small feature on paper but, without it, one of the funniest features of Better TweetDeck wouldn&#x27;t have been possible years later. &#x3C;em&#x3E;~Foreshadowing~&#x3C;/em&#x3E;.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;opera-support&#x22;&#x3E;Opera support&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;3.0.17, September 2016&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;3.0.17 in itself was fairly light on features, but it also marked the first instance of non-Chrome browser support: Opera! On a technical side, I remember it being easy enough to support, since Opera had recently(? I think) switched to Chromium/Blink, so extensions worked as-is.&#x3C;br /&#x3E;
However, the Opera Add-ons Store was &#x3C;em&#x3E;a pain&#x3C;/em&#x3E; to work with. I could never get reliable reviews in a reasonable time, meaning Opera users were always days, if not weeks, behind Chrome users.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://twitter.com/BetterTDeck/status/1098087699993354240&#x22;&#x3E;Three years later&#x3C;/a&#x3E;, I ended up removing the extension from Opera&#x27;s store because of the review hassles. I could write a whole blog post about my experiences with different browser extension stores and platforms &#x1F605;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;3x&#x22;&#x3E;3.x&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;2017&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Quite a bit had happened after 3.0:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;The messages in the Direct Messages column could be collapsed, a very neat and useful trick. One of many contributions by &#x3C;a href=&#x22;https://github.com/pixeldesu&#x22;&#x3E;pixeldesu&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;A lot of thumbnail providers were contributed by folks! Mostly for Japanese-speaking sites. That might explain why BTD ended up being so popular with Japanese users.
&#x3C;ul&#x3E;
&#x3C;li&#x3E;For the curious, those providers were WorldCosplay, Photozou, Gyazo, TINAMI, Nicoseiga, Miil.me and... Google+.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;Donald Trump had taken office a few months prior and, things were looking grim in the U.S., so I used my (albeit tiny) platform to promote some organizations doing the good work on my donation page. I never needed BTD to make money in order to work on it, so it felt like the right thing to do.&#x3C;/li&#x3E;
&#x3C;li&#x3E;A bunch of things around GIFs:
&#x3C;ul&#x3E;
&#x3C;li&#x3E;Ability to view GIFs in full-screen. A feature that I wish more social media sites copied, sometimes a GIF is actually a video, and it would be very useful to zoom in on it!&#x3C;/li&#x3E;
&#x3C;li&#x3E;GIF download! This one was useful but also a pain in the ass. It was based on a &#x3C;a href=&#x22;https://www.npmjs.com/package/gifshot&#x22;&#x3E;barely maintained library from Yahoo&#x3C;/a&#x3E; and worked well about 80% of the time. Turns out converting MP4 files to GIF files is much harder than you might think. I ended up removing that feature a few years later because it was also &#x3C;em&#x3E;very slow&#x3C;/em&#x3E; on some browsers.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;Image pasting into the composer. A feature that&#x27;s basically a given on any website these days, but TweetDeck never got that, for some reason, which is a shame because my implementation was &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/blob/3.1.0/src/js/inject.js#L335-L362&#x22;&#x3E;really simple&#x3C;/a&#x3E;.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;h3 id=&#x22;firefox-support&#x22;&#x3E;Firefox support!&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;3.3.4, May 2017&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Firefox support had been a common request ever since Better TweetDeck was released in 2014. But the fact was, Firefox had a completely different extension architecture, meaning I would need to accommodate both in a single codebase, somehow. That wasn&#x27;t happening.&#x3C;br /&#x3E;
Thankfully, Mozilla was working on implementing the &#x3C;a href=&#x22;https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions&#x22;&#x3E;WebExtensions API&#x3C;/a&#x3E; with the goal of reaching parity with Chrome. This was great news because it meant I could easily support both Chrome and Firefox with minimal platform-specific changes &#x1F604;&#x3C;/p&#x3E;
&#x3C;p&#x3E;After quite a bit of back and forth in initial reviews with the Mozilla Add-ons team, Better TweetDeck landed on Firefox in May 2017!&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/btd-post-mortem2/btd-firefox.jpg&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-firefox.jpg&#x22; alt=&#x22;Better TweetDeck 3.3.4 running on Firefox 52&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Better TweetDeck 3.3.4 running on Firefox 52&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;the-one-with-the-edit-button&#x22;&#x3E;The one with the &#x22;Edit button&#x22;&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;3.4.6-3.4.7, October 2017&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;One recurring theme of Better TweetDeck was that I wasn&#x27;t very good at versioning, since, in hindsight these &#x22;patch&#x22; versions deserved to be more than that. After all, they brought fan-favorite features, all of which were contributed by &#x3C;a href=&#x22;https://github.com/EntranceJew&#x22;&#x3E;EntranceJew&#x3C;/a&#x3E;. I wish I came up with at least &#x3C;em&#x3E;one&#x3C;/em&#x3E; of these myself!&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;collapsible-columns-and-clear-button-in-columns-header&#x22;&#x3E;Collapsible columns and &#x22;clear&#x22; button in columns&#x27; header&#x3C;/h4&#x3E;
&#x3C;ol&#x3E;
&#x3C;li&#x3E;&#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/pull/208&#x22;&#x3E;Collapsible columns&#x3C;/a&#x3E;. This was a good alternative to deleting a column, because sometimes you wanted to just &#x22;hide&#x22; a column temporarily, or just needed to clean up your view.&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/pull/224&#x22;&#x3E;&#x22;Clear&#x22; button in the columns&#x27; header&#x3C;/a&#x3E;. On its own, it was a small improvement, but I built on top of it to add more actions in that area later.&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;figure data-type=&#x22;video&#x22;&#x3E;
&#x3C;video src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-collapsible-columns.mp4&#x22; poster=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-collapsible-columns.jpg&#x22; playsinline controls&#x3E;&#x3C;/video&#x3E;
&#x3C;figcaption&#x3E;
  A demo of Better TweetDeck&#x27;s collapsible columns in action. Enjoy the &#x22;retro&#x22; Chrome UI as a bonus.
&#x3C;/figcaption&#x3E;
&#x3C;/figure&#x3E;
&#x3C;h4 id=&#x22;the-edit-button&#x22;&#x3E;The &#x22;Edit&#x22; button&#x3C;/h4&#x3E;
&#x3C;p&#x3E;Honestly EntranceJew&#x27;s best idea and the one that had the most impact for Better TweetDeck users and &#x3C;a href=&#x22;https://blog.joinmastodon.org/2018/06/if-you-could-edit-tweets/&#x22;&#x3E;everyone&#x3C;/a&#x3E; &#x3C;a href=&#x22;https://www.theverge.com/2023/2/14/23600047/tweetbot-creators-mastodon-ivory-edit-button&#x22;&#x3E;else&#x3C;/a&#x3E;. It was more of a &#x22;re-draft&#x22; feature more than anything else since it copied your tweet&#x27;s text and media, deleted it and re-opened the composer with everything pre-filled.&#x3C;br /&#x3E;
I probably should have changed the button&#x27;s label to &#x22;Re-draft&#x22;, but then I wouldn&#x27;t have ended up in a &#x3C;a href=&#x22;https://www.buzzfeednews.com/article/janelytvynenko/twitter-is-not-testing-an-edit-button&#x22;&#x3E;BuzzFeed&#x3C;/a&#x3E; story so who can say!&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;the-gif-and-emoji-update&#x22;&#x3E;The GIF and emoji update&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;3.5, December 2017&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;This time, I had properly versioned the version since it added two pretty &#x22;big&#x22; features:&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;emoji-short-codes-in-the-composer&#x22;&#x3E;Emoji short codes in the composer&#x3C;/h4&#x3E;
&#x3C;p&#x3E;A long-time request and one of my favorite features. If you&#x27;ve used Slack, Discord or Mastodon, you know what this does, otherwise, look at the video below!&#x3C;/p&#x3E;
&#x3C;figure data-type=&#x22;video&#x22;&#x3E;
&#x3C;video src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-emoji-shortcodes.mp4&#x22; poster=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-emoji-shortcodes.jpg&#x22; playsinline controls&#x3E;&#x3C;/video&#x3E;
&#x3C;figcaption&#x3E;
  A demo of the emoji autocompletion feature
&#x3C;/figcaption&#x3E;
&#x3C;/figure&#x3E;
&#x3C;h4 id=&#x22;gif-picker&#x22;&#x3E;GIF picker&#x3C;/h4&#x3E;
&#x3C;p&#x3E;Another long requested feature. It was a bit of a mess to implement at the time but was well worth it. It also let me introduce a subtle but &#x3C;a href=&#x22;https://twitter.com/search?q=%40Bettertdeck%20jif&#x26;amp;src=typed_query&#x26;amp;f=live&#x22;&#x3E;effective April Fools&#x27; joke&#x3C;/a&#x3E; in Better TweetDeck &#x1F604;&#x3C;/p&#x3E;
&#x3C;figure data-type=&#x22;video&#x22;&#x3E;
&#x3C;video src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-gif-picker.mp4&#x22; poster=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-gif-picker.jpg&#x22; playsinline controls&#x3E;&#x3C;/video&#x3E;
&#x3C;figcaption&#x3E;
  A demo of the emoji autocompletion feature
&#x3C;/figcaption&#x3E;
&#x3C;/figure&#x3E;
&#x3C;h3 id=&#x22;advanced-mute-engines-debut-and-the-old-dark-theme&#x22;&#x3E;Advanced Mute Engine&#x27;s debut and the old dark theme.&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;3.6, February 2018&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Another big update with external contributions! This time, &#x3C;a href=&#x22;https://github.com/pixeldesu&#x22;&#x3E;pixeldesu&#x3C;/a&#x3E; cooked up a feature that ended up being the backbone of many useful additions later on: the &#x22;Advanced Mute Engine&#x22;. Without going into the technical details, it was a system running on top of TweetDeck&#x27;s mute engine.&#x3C;br /&#x3E;
This may sound weird nowadays, but TweetDeck had mute capabilities way before the rest of Twitter did! TweetDeck&#x27;s system running entirely client-side (in a user&#x27;s browser) meant that Better TweetDeck could plug into it to add extra functionality. In this first update you could:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;Mute tweets by keywords from a specific user&#x3C;/li&#x3E;
&#x3C;li&#x3E;Mute with regular expressions&#x3C;/li&#x3E;
&#x3C;li&#x3E;Mute people based on keywords in their bio&#x3C;/li&#x3E;
&#x3C;li&#x3E;Mute users with the default profile picture&#x3C;/li&#x3E;
&#x3C;li&#x3E;Mute users with less than &#x3C;em&#x3E;n&#x3C;/em&#x3E; followers&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;Those options showed up as options in the &#x22;Mute&#x22; tab of TweetDeck&#x27;s settings:&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/btd-post-mortem2/btd-advanced-mute.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-advanced-mute.png&#x22; alt=&#x22;Better TweetDeck&#x27;s Advanced Mute Engine additions&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Better TweetDeck&#x27;s Advanced Mute Engine additions&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Over time, pixeldesu and I ended up adding more specific/&#x22;niche&#x22; muting options to that menu.&#x3C;/p&#x3E;
&#x3C;p&#x3E;However, this release also happened at the same time that Twitter switched TweetDeck&#x27;s dark &#x22;gray&#x22; theme to a more blueish dark theme palette. I personally didn&#x27;t mind much, but &#x3C;em&#x3E;a lot&#x3C;/em&#x3E; of people cared and preferred the old way things looked, so I pretty much embedded a copy of TweetDeck&#x27;s old CSS file in Better TweetDeck to support that. It worked but was kind of a messy solution to a problem that &#x2014;I imagine&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-11&#x22; id=&#x22;user-content-fnref-11&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;7&#x3C;/a&#x3E;&#x3C;/sup&#x3E;&#x2014; only a fraction of my user base had &#x1F643;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;custom-css&#x22;&#x3E;Custom CSS&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;3.7, May 2018&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;3.7.0 was a smaller update but saw support for another long-requested feature: Custom CSS! I avoided implementing this for a long time because extensions like &#x3C;a href=&#x22;https://add0n.com/stylus.html&#x22;&#x3E;Stylus&#x3C;/a&#x3E; do the job better, but I guess not everybody wanted to install a whole other extension &#x3C;em&#x3E;just&#x3C;/em&#x3E; to apply a few CSS tweaks.&#x3C;/p&#x3E;
&#x3C;p&#x3E;So I added that feature in, and took this as an opportunity to play around with &#x3C;a href=&#x22;https://microsoft.github.io/monaco-editor/&#x22;&#x3E;Monaco&#x3C;/a&#x3E;, the code editor that powers &#x3C;a href=&#x22;https://code.visualstudio.com/&#x22;&#x3E;Visual Studio Code&#x3C;/a&#x3E;.&#x3C;br /&#x3E;
Users were also sharing &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/issues/546&#x22;&#x3E;their own personal tweaks&#x3C;/a&#x3E; to TweetDeck&#x27;s UI as well, which is always neat to see.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;putting-a-one-face-behind-tweetdeck&#x22;&#x3E;Putting a (one) face behind TweetDeck&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;August 2018&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;2018 wasn&#x27;t a quiet year for me (more on that later), but one of the highlights was being able to finally put a (at least one) face behind TweetDeck! You see, in 2018, Twitter held a company-wide event called &#x22;#OneTeam&#x22;, where most (all?) the teams would meet up at HQ in San Francisco. That&#x27;s when I got to meet &#x3C;a href=&#x22;https://twitter.com/andrs&#x22;&#x3E;Andreas&#x3C;/a&#x3E; who was TweetDeck&#x27;s Tech Lead at the time.&#x3C;/p&#x3E;
&#x3C;p&#x3E;It has been 5 years, so I obviously don&#x27;t remember every detail from our conversation, but I got the same feeling I had from my other interactions with him and other members of the TweetDeck team prior: it is was a small but mighty team who cared about their work and was very much aware of what I was doing with Better TweetDeck.&#x3C;br /&#x3E;
It was all pie-in-the-sky thinking but I remember Andreas imagining an &#x22;add-ons&#x22; system that third parties (like me) could take advantage of to add functionality to TweetDeck. At this point I wasn&#x27;t the only project extending TweetDeck anymore. &#x3C;a href=&#x22;https://github.com/dangeredwolf/ModernDeck&#x22;&#x3E;ModernDeck&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://tweetduck.chylex.com/&#x22;&#x3E;TweetDuck&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://tweetenapp.com/&#x22;&#x3E;Tweeten&#x3C;/a&#x3E;, among others, were filling specific niches with different ideas for the app. It was an interesting time to build on top of TweetDeck!&#x3C;/p&#x3E;
&#x3C;p&#x3E;Those good relations and interactions were also the reason why I refrained from publicly venting/berating the TweetDeck team on behalf of Better TweetDeck. The team was small and, at this point, I knew a couple of people there, so, if I talked shit, they &#x3C;em&#x3E;would&#x3C;/em&#x3E; know.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;cleaning-up-and-adopting-typescript&#x22;&#x3E;Cleaning up and adopting TypeScript&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;4.0, April 2021&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;2018 was a very busy (and stressful) year for me at work, since it was the year we decided to rewrite our entire frontend, switching from &#x3C;a href=&#x22;https://angularjs.org/&#x22;&#x3E;AngularJS&#x3C;/a&#x3E; to &#x3C;a href=&#x22;https://react.dev/&#x22;&#x3E;React&#x3C;/a&#x3E;. I won&#x27;t go into the details of that transition in this post but, if you take a quick look at &#x3C;a href=&#x22;https://front.com&#x22;&#x3E;Front&#x3C;/a&#x3E;&#x27;s website, you can imagine how big the effort was.
However, despite the hardships and the large amount of work, I learned a lot about React (even though I had already used it in a previous project that served as a &#x22;proof of concept&#x22;) and, more importantly, &#x3C;a href=&#x22;https://www.typescriptlang.org/&#x22;&#x3E;TypeScript&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;As soon as the migration work was close to being done, I knew I wanted to rewrite Better TweetDeck in TypeScript. The advantages, safety and creature comforts it brought were 100% worth the learning curve, so I knew it would be a good fit for Better TweetDeck as well.
I think I can&#x27;t see myself writing any sizeable app without it. The safety and peace of mind it brings are just too good to pass up. When you&#x27;ve made a massive refactor with only its compiler running, and &#x3C;em&#x3E;nothing&#x3C;/em&#x3E; breaks when you launch the app for the first time after days of work, it feels like magic.&#x3C;/p&#x3E;
&#x3C;p&#x3E;However, Better TweetDeck had become a bigger project than it was when I first rewrote it from 1.0 to 2.0, years earlier, which meant that a rewrite was no easy task!&#x3C;br /&#x3E;
Or, now that I think about: no, rewriting the code itself was the easy part. Knowing &#x3C;em&#x3E;how&#x3C;/em&#x3E;, &#x3C;em&#x3E;what&#x3C;/em&#x3E; to change and &#x3C;em&#x3E;why&#x3C;/em&#x3E; in a rewrite was the hard part. For a while I couldn&#x27;t reach that point. I would always rewrite some core parts of Better TweetDeck&#x27;s codebase, but it brought little to no benefits, so I would be spinning my wheels.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The timeline is a bit hazy in my head, but I suppose things must have clicked in place around the end of 2020, since I ended up releasing 4.0.0 in April 2021.&#x3C;br /&#x3E;
At any rate, 4.0.0 came with a &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/releases/tag/4.0.0&#x22;&#x3E;&#x3C;em&#x3E;bunch&#x3C;/em&#x3E; of features&#x3C;/a&#x3E; on top of the technical changes that made it faster and easier to maintain.&#x3C;/p&#x3E;
&#x3C;p&#x3E;I don&#x27;t want to say the project&#x27;s codebase was perfect because, looking back, there are things I wish I did differently, or that I probably shouldn&#x27;t have done myself, but I was pretty happy with the results!&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;getting-silly-with-it&#x22;&#x3E;Getting silly with it&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;4.2.0, June 2021&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;The switch to a TypeScript codebase really paid dividends, as it meant I could add features more easily and have fun with it. One of those features was the customization of the &#x22;logo&#x22; in the bottom left of TweetDeck&#x27;s UI!&#x3C;/p&#x3E;
&#x3C;p&#x3E;This started with the fact that TweetDeck, for a few years prior that, had been replacing the &#x3C;a href=&#x22;/img/blog/btd-post-mortem2/tweetdeck-logo96.png&#x22;&#x3E;regular logo&#x3C;/a&#x3E; with a &#x3C;a href=&#x22;/img/blog/btd-post-mortem2/tweetdeck-pride.2019.svg&#x22;&#x3E;Pride-themed variant&#x3C;/a&#x3E; during &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Pride_in_London?useskin=vector&#x22;&#x3E;London Pride&#x3C;/a&#x3E; in July. If you&#x27;re wondering why London Pride in July and not June with Pride month like the US, that is because (most of) the TweetDeck team was based in London!&#x3C;/p&#x3E;
&#x3C;p&#x3E;Anyway, I thought it would be fun to riff on that and offer multiple variants in Better TweetDeck. It would only be visible to the user themselves, of course, but people liked it a lot, which made it worth it. It also made the weirdest, most annoying people mad, which is very funny.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/btd-post-mortem2/btd-pride-settings.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-pride-settings.png&#x22; alt=&#x22;The list of different logos that the user could choose from in Better TweetDeck 4.2.0&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;The list of different logos that the user could choose from in Better TweetDeck 4.2.0&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;tweetdeck-beta&#x22;&#x3E;TweetDeck Beta&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;July 2021&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;What is now sold behind a paywall as &#x22;XPro&#x22;, used to be called &#x3C;a href=&#x22;https://www.theverge.com/2021/7/20/22585249/tweetdeck-redesign-twitter-column-deck&#x22;&#x3E;TweetDeck Beta&#x3C;/a&#x3E;; the existence of which was &#x3C;a href=&#x22;https://www.theverge.com/2021/3/9/22321991/twitter-tweetdeck-overhaul-redesign-product-changes&#x22;&#x3E;hinted at&#x3C;/a&#x3E; for quite a while before Twitter started making it available in July 2021. After being able to &#x3C;a href=&#x22;https://twitter.com/Eramdam/status/1417505836662853633&#x22;&#x3E;get in&#x3C;/a&#x3E;, I got rolled in in order to try it in a more &#x22;official&#x22; manner. As mentioned before, the TweetDeck team knew I&#x27;d be curious to check it out and was actually curious to hear my thoughts! I had... a &#x3C;a href=&#x22;https://twitter.com/Eramdam/status/1417507455907426304&#x22;&#x3E;lot of them&#x3C;/a&#x3E;. And in a funny way, most of them are still valid, because it has barely evolved since then!&#x3C;/p&#x3E;
&#x3C;p&#x3E;From July until the end of 2021, I was in communication with the TweetDeck team about:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;what I thought of the Beta itself. I still think it was promising and it could have been a worthy replacement if the team had been given time and resources to make it good, which didn&#x27;t happen.&#x3C;/li&#x3E;
&#x3C;li&#x3E;what the Beta needed to be &#x22;competitive&#x22; with current TweetDeck. True multi-accounts was a must, at the very least. This wouldn&#x27;t come until the middle of 2023, long after Elon Musk fired most of the TweetDeck team, leaving it down to a skeleton crew.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;During those conversations, I got the impression that the team really wanted to deliver their best work with this Beta. They seemed aware of what needed to improve to satisfy the userbase at the time. I was still on the fence about whether or not Better TweetDeck would try to support this Beta, should it become the main TweetDeck experience, and they even expressed the wish of making it easier for me to extend it later down the line! I was inclined to believe them, because it was consistent with the attitude I had seen towards Better TweetDeck from other team members in the past.&#x3C;/p&#x3E;
&#x3C;p&#x3E;It wouldn&#x27;t be the last time I&#x27;d hear about TweetDeck Beta, but I&#x27;ll touch on that later.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;content-warnings-and-pronouns&#x22;&#x3E;Content warnings and pronouns&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;July - November 2021&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;In a completely detached vein from the one Twitter would eventually follow, I added two of my (still) favorite features to Better TweetDeck.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The first one being &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/pull/483&#x22;&#x3E;content warning detection&#x3C;/a&#x3E;. It was another great idea by &#x3C;a href=&#x22;https://github.com/pixeldesu&#x22;&#x3E;pixeldesu&#x3C;/a&#x3E; who contributed the basic idea/implementation, which I then ported over the v4 codebase. I would have merged it wholesale but it took me so long to work on v4 that his PR was impossible to merge quickly &#x1F605;&#x3C;br /&#x3E;
If you are unaware, it was a workaround to the fact that Twitter still doesn&#x27;t have any good way of marking the content of a tweet as sensitive, which led people to using a syntax like &#x22;cw // phobia&#x22; to indicate sensitive content.
This PR interpreted the syntax and presented a Mastodon-like UI to toggle the display of the content in question, pretty good stuff!&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/btd-post-mortem2/btd-content-warnings.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-content-warnings.png&#x22; alt=&#x22;Screenshot showing the Content Warning detection in practice at an earlier stage of development&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Screenshot showing the Content Warning detection in practice at an earlier stage of development&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;The second one was &#x3C;a href=&#x22;https://twitter.com/BetterTDeck/status/1455252017996201984&#x22;&#x3E;pronoun extraction&#x3C;/a&#x3E; (sic), which, like the name implies, grabbed pronouns from users&#x27; bio and location fields and displayed them above their tweets.
It&#x27;s the kind of feature whose &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/blob/main/src/features/pronounsDisplay.ts&#x22;&#x3E;implementation&#x3C;/a&#x3E; is more complex than one may think but which looks very simple when used.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;/img/blog/btd-post-mortem2/btd-pronouns-display.png&#x22;&#x3E;&#x3C;img src=&#x22;https://damien.zone/img/blog/btd-post-mortem2/btd-pronouns-display.png&#x22; alt=&#x22;Screenshot showing the pronouns display in practice&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Screenshot showing the pronouns display in practice&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;It&#x27;s also another feature that I &#x3C;em&#x3E;knew&#x3C;/em&#x3E; the TweetDeck/Twitter folks were aware of, because one engineer there told me they saw it, and Twitter ended up testing an &#x3C;a href=&#x22;https://twitter.com/uwukko/status/1515618844244590592&#x22;&#x3E;actual pronouns field&#x3C;/a&#x3E; later on! But alas, I doubt this will ever materialize under Twitter&#x27;s current administration.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;no-fucking-thanks&#x22;&#x3E;No Fucking Thanks&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;November 2021&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;2021 also saw the rise of cryptocurrencies and other blockchain bullshit. Despite the technology itself being pretty old at this point (Bitcoin was picking up steam when I was still a student in 2013, for crying out loud!), &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Non-fungible_token?useskin=vector&#x22;&#x3E;NFTs&#x3C;/a&#x3E; were seemingly everywhere and poised to revolutionize everything that had to do with computers &#x1F644;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Thankfully, the whole crypto space is now recognized for the joke and fraud that it is but, back then, Twitter felt the need to jump onto the craze and &#x3C;a href=&#x22;https://twitter.com/TheSmarmyBum/status/1443259893411049475&#x22;&#x3E;allow users to use their NFTs as avatars&#x3C;/a&#x3E;. I allowed Better TweetDeck users to mute those accounts as soon as &#x3C;a href=&#x22;https://twitter.com/BetterTDeck/status/1465505226044018700&#x22;&#x3E;technically possible&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Unsurprisingly, crypto people &#x2014;who had otherwise never heard of me or my projects&#x2014; took it upon themselves to decide I was enemy #1, and deemed it worthy of their time to harass me for implementing a silly little switch in my dinky little extension. Go figure &#x1F937;&#x200D;&#x2642;&#xFE0F;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Sure, I could have been more diplomatic about the whole thing (I did kick the hornet&#x27;s nest pretty hard on my first iteration of the feature), but it&#x27;s still funny to me that a crowd who supposedly were pioneering a &#x22;new age of computing and finance&#x22; felt threatened by an open-source project with maybe 50,000 users tops.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Clown stuff. Anyway, the harassment fortunately didn&#x27;t last very long and was curbed pretty quickly thanks to &#x3C;a href=&#x22;https://www.blockpartyapp.com/&#x22;&#x3E;BlockParty&#x3C;/a&#x3E;. And as I&#x27;m writing this, &#x3C;a href=&#x22;https://web3isgoinggreat.com/?id=twitter-removes-nft-profile-picture-support&#x22;&#x3E;Twitter dropped the feature entirely&#x3C;/a&#x3E;, good riddance.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Later on, I would add a UI that let users see what users the mute filters they set up &#x22;caught&#x22;. A lot of folks wanted me to implement an auto-blocking mechanism, but I didn&#x27;t want to work around Twitter&#x27;s very strict rate limits around blocking, and also wanted to be able to sleep at night knowing I didn&#x27;t ship a bug that made my code block a whole bunch of people by mistake. So this &#x22;mute catching&#x22; thing was the best compromise IMO since it would let people export the list of users to a format that tools like BlockParty could use to mass-block accounts.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;https://user-images.githubusercontent.com/1409924/147862067-416852b7-2f1c-483a-bbed-389972881765.png&#x22;&#x3E;&#x3C;img src=&#x22;https://user-images.githubusercontent.com/1409924/147862067-416852b7-2f1c-483a-bbed-389972881765.png&#x22; alt=&#x22;Screenshot of the mute catches modal in Better TweetDeck 4.7.0&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Screenshot of the mute catches modal in Better TweetDeck 4.7.0&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;dawn-of-the-final-year&#x22;&#x3E;Dawn of the Final Year&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;Most of 2022&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;2022 was a lot. It was kind of overwhelming on a personal level due to uninteresting reasons (Immigration is fun and definitely not anxiety-inducing!) but as you may know if you used Twitter then, that was also the start of Elon&#x27;s deranged arc that ended with him buying the company and killing it.&#x3C;/p&#x3E;
&#x3C;p&#x3E;Anyway, the first half of the year was pretty quiet on the Better TweetDeck side. I had started experimenting with making my own web-based Twitter client, obviously inspired by TweetDeck. The reasoning was that I understood pretty quickly that TweetDeck Beta would make Better TweetDeck impossible to use, so I preferred spending energy on creating something from scratch. It didn&#x27;t really go anywhere because:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;Twitter&#x27;s API was already in a bad enough shape that it would&#x27;ve been impossible to get to a satisfying point feature-wise.&#x3C;/li&#x3E;
&#x3C;li&#x3E;I also made things harder for myself by wanting to support Twitter &#x3C;strong&#x3E;and&#x3C;/strong&#x3E; Mastodon.&#x3C;/li&#x3E;
&#x3C;li&#x3E;Making a whole-ass TweetDeck-like web app takes work! Who knew!&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;At the very least, it was a good distraction amidst the &#x3C;a href=&#x22;https://twitter.com/MacRumors/status/1518664496138518528&#x22;&#x3E;madness&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The rest of 2022 was pretty uneventful on Better TweetDeck&#x27;s side, until...&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;the-beginning-of-the-end&#x22;&#x3E;The beginning of the end&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;September - November 2022&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;In early September 2022, I made peace with the fact that Better TweetDeck in its current form was going to die as soon as TweetDeck Beta dropped. I &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/issues/848&#x22;&#x3E;posted about it&#x3C;/a&#x3E; and decided Better TweetDeck was in a &#x22;feature freeze&#x22; mode, where I would only fix the most pressing bugs until the very end.&#x3C;/p&#x3E;
&#x3C;p&#x3E;There was still uncertainty around whether or not Musk would end up buying Twitter. Alas it happened in November. With it came the first of many stupid changes, which was offering &#x22;verification&#x22; for an 8$/month subscription.&#x3C;/p&#x3E;
&#x3C;p&#x3E;This was a very silly decision, so I decided to make fun of it in what would be the last major feature update for Better TweetDeck.&#x3C;/p&#x3E;
&#x3C;p&#x3E;&#x3C;/p&#x3E;&#x3C;figure data-type=&#x22;image&#x22;&#x3E;&#x3C;a href=&#x22;https://user-images.githubusercontent.com/1409924/201475115-71e23d45-63e7-416d-a993-ee5ec22aba1b.png&#x22;&#x3E;&#x3C;img src=&#x22;https://user-images.githubusercontent.com/1409924/201475115-71e23d45-63e7-416d-a993-ee5ec22aba1b.png&#x22; alt=&#x22;Setting to change the checkmark icon for &#x26;quot;Blue verified&#x26;quot; users&#x22; loading=&#x22;lazy&#x22; decoding=&#x22;async&#x22; width=&#x22;auto&#x22; height=&#x22;auto&#x22; /&#x3E;&#x3C;/a&#x3E;&#x3C;figcaption&#x3E;Setting to change the checkmark icon for &#x22;Blue verified&#x22; users&#x3C;/figcaption&#x3E;&#x3C;/figure&#x3E;&#x3C;p&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;Unsurprisingly, this made some of the most boring people on Earth (those who want to pay 8 bucks to feel important online) very upset, so it was well worth it.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;slow-death&#x22;&#x3E;Slow Death&#x3C;/h3&#x3E;
&#x3C;p&#x3E;&#x3C;small&#x3E;2023&#x3C;/small&#x3E;&#x3C;/p&#x3E;
&#x3C;p&#x3E;And that brings us to the end of Better TweetDeck. Like I said above, Elon Musk took over, fired a bunch of Twitter&#x27;s workforce, and killed third party clients, convincing me it wasn&#x27;t worth my time to build on top of Twitter&#x27;s service.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The rest of the year was a mess as far as Twitter goes, but TweetDeck stayed, inexplicably, unaffected. Until July of 2023 when Twitter first &#x3C;a href=&#x22;https://www.theverge.com/2023/7/3/23782585/tweetdeck-broken-twitter-rate-limits-scraping-elon-musk&#x22;&#x3E;killed it by mistake&#x3C;/a&#x3E; and then &#x3C;a href=&#x22;https://www.theverge.com/2023/7/3/23783092/twitter-tweetdeck-new-preview-force-legacy-apis&#x22;&#x3E;announced&#x3C;/a&#x3E; the new version would be locked behind Twitter Blue, announcing that, 30 days later, TweetDeck Beta would be the &#x3C;strong&#x3E;only&#x3C;/strong&#x3E; TweetDeck and would require a Twitter Blue subscription.&#x3C;/p&#x3E;
&#x3C;p&#x3E;In early August, after their stupid rebranding to X, &#x3C;a href=&#x22;https://www.theverge.com/2023/8/15/23833707/tweetdeck-xpro-paid-service-x-premium-twitter&#x22;&#x3E;Twitter would rename TweetDeck to XPro and force the new UI onto everyone willing to pay for a subscription&#x3C;/a&#x3E;, killing Better TweetDeck for good.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;parting-words&#x22;&#x3E;Parting words&#x3C;/h2&#x3E;
&#x3C;p&#x3E;And here we are, back to the present day (pretend this blog post didn&#x27;t take me 5 months to write). If it weren&#x27;t for all of this, Better TweetDeck would be ten years old at the end of January.&#x3C;br /&#x3E;
It is completely mind-blowing to me that I spent that long working on, caring about and sharing this project with people!&#x3C;/p&#x3E;
&#x3C;p&#x3E;While I was the main contributor for a while, all of this wouldn&#x27;t have been possible without the contributions of a lot people!&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://synthetic.garden/&#x22;&#x3E;twilight sparkle&#x3C;/a&#x3E; who wrote &#x3C;a href=&#x22;https://gist.github.com/twilight-sparkle-irl/cb63762000e606e50690911cac1bcead&#x22;&#x3E;&#x3C;code&#x3E;webcrack&#x3C;/code&#x3E;&#x3C;/a&#x3E;, which allowed to modify TweetDeck&#x27;s modules at runtime. Without that work, most of Better TweetDeck&#x27;s most interesting features wouldn&#x27;t have been possible at all.&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://github.com/pixeldesu&#x22;&#x3E;pixeldesu&#x3C;/a&#x3E;, for helping, supporting and contributing some critical features, as well as creating and maintaining &#x3C;a href=&#x22;https://github.com/pixeldesu/moduleRaid&#x22;&#x3E;moduleRaid&#x3C;/a&#x3E;, a successor to the aforementioned &#x3C;code&#x3E;webcrack&#x3C;/code&#x3E;. moduleRaid was invaluable when digging through TweetDeck&#x27;s code and made a lot of recent features possible. Andy also created &#x3C;a href=&#x22;https://github.com/deckhack&#x22;&#x3E;DeckHack&#x3C;/a&#x3E; which was a small group of TweetDeck-focused developers where we&#x27;d discuss how to break mess around with TweetDeck.&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://github.com/dangeredwolf/&#x22;&#x3E;dangered wolf&#x3C;/a&#x3E; for their work on &#x3C;a href=&#x22;https://github.com/DeckHack/TweetDeck-Decompiler&#x22;&#x3E;TweetDeck-Decompiler&#x3C;/a&#x3E;. As the name implies, this let me quickly inspect TweetDeck&#x27;s JavaScript code and figure out where to poke to do what I wanted to &#x1F604;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=EntranceJew&#x22;&#x3E;EntranceJew&#x3C;/a&#x3E; for the &#x22;edit&#x22; button feature and a whole lot more &#x1F64F;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=shuuji3&#x22;&#x3E;shuuji3&#x3C;/a&#x3E; for their help localizing Better TweetDeck into Japanese and early thumbnail provider support for Gyazo, Niceoseiga, TINAMI, WorldCosplay, Photozou, twipple and Pixiv.&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://github.com/apps/dependabot&#x22;&#x3E;dependabot&#x3C;/a&#x3E;, for the pesky dependency upgrade reminders &#x1F62A;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://twitter.com/luciascarlet/status/1590462560515473409&#x22;&#x3E;lucia scarlet&#x3C;/a&#x3E; for the &#x22;nerd emoji&#x22; badge.&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;
&#x3C;p&#x3E;&#x3C;a href=&#x22;https://twitter.com/JoshQuake/status/1590634793393614849&#x22;&#x3E;JoshQuake&#x3C;/a&#x3E; for the clown badge.&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li&#x3E;
&#x3C;p&#x3E;As well as the following people for smaller contributions to the codebase &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=LeoColomb&#x22;&#x3E;LeoColomb&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=hiroto7&#x22;&#x3E;hiroto7&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=emadgh&#x22;&#x3E;emadgh&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=outadoc&#x22;&#x3E;outadoc&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=noriokun4649&#x22;&#x3E;noriokun4649&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=chylex&#x22;&#x3E;chylex&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=Sophia2329&#x22;&#x3E;Sophia2329&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=d4rky-pl&#x22;&#x3E;d4rky-pl&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=miestasmia&#x22;&#x3E;miestasmia&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=knu&#x22;&#x3E;knu&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=viki53&#x22;&#x3E;viki53&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=katabame&#x22;&#x3E;katabame&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=ngdio&#x22;&#x3E;ngdio&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=Floppy012&#x22;&#x3E;Floppy012&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=mika-f&#x22;&#x3E;mika-f&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=zenmaibane&#x22;&#x3E;zenmaibane&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=resir014&#x22;&#x3E;resir014&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=babolivier&#x22;&#x3E;babolivier&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=Jaid&#x22;&#x3E;Jaid&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=Lycolia&#x22;&#x3E;Lycolia&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=yaa&#x22;&#x3E;yaa&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=CommanderRoot&#x22;&#x3E;CommanderRoot&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=nullpixel&#x22;&#x3E;nullpixel&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=Vogeslu&#x22;&#x3E;Vogeslu&#x3C;/a&#x3E; and &#x3C;a href=&#x22;https://github.com/eramdam/BetterTweetDeck/commits?author=izzy&#x22;&#x3E;izzy&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;But also... you! This isn&#x27;t just me being corny. For the longest time, Better TweetDeck had no real &#x22;marketing&#x22; and the most it got was banners in the Chrome Web Store. So, if you used Better TweetDeck and spread the word about it in any capacity, &#x3C;strong&#x3E;thank you&#x3C;/strong&#x3E;! None of this would have been possible without you and I&#x27;m grateful for it &#x2764;&#xFE0F;&#x3C;/p&#x3E;
&#x3C;p&#x3E;I want to try to keep using this blog more regularly, so feel free to add it to your RSS reader (remember those?) or &#x3C;a href=&#x22;/links&#x22;&#x3E;find me online&#x3C;/a&#x3E; to know when I post something!&#x3C;/p&#x3E;
&#x3C;p&#x3E;So long, and thanks for all the fish! &#x1F42C;&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-3&#x22;&#x3E;
&#x3C;p&#x3E;They will probably recognize themselves if they&#x27;re reading this &#x1F604; &#x3C;a href=&#x22;#user-content-fnref-3&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-6&#x22;&#x3E;
&#x3C;p&#x3E;Typing this out is very funny when you think about the fact there are around 3,500 emoji now! &#x3C;a href=&#x22;#user-content-fnref-6&#x22; data-footnote-backref aria-label=&#x22;Back to reference 2&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-7&#x22;&#x3E;
&#x3C;p&#x3E;Here&#x27;s a &#x3C;a href=&#x22;/btd/btd-graph&#x22;&#x3E;link&#x3C;/a&#x3E; to a chart showing that data. Surely there&#x27;s a way to present it in a nicer way, but I don&#x27;t know how &#x1F605; &#x3C;a href=&#x22;#user-content-fnref-7&#x22; data-footnote-backref aria-label=&#x22;Back to reference 3&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-8&#x22;&#x3E;
&#x3C;p&#x3E;Despite being fresh out of university at the time, I had already worked on a few freelance projects, as well as a project you &#x3C;a href=&#x22;https://dribbble.com/shots/176127-VLC-for-OS-X-Lion-style&#x22;&#x3E;may&#x3C;/a&#x3E; &#x3C;a href=&#x22;https://dribbble.com/shots/196481-VLC-QuickTime-X-Like&#x22;&#x3E;know&#x3C;/a&#x3E; &#x3C;a href=&#x22;https://dribbble.com/shots/1734291-VLC-on-Yosemite-dark-mode-and-sidebar-icons&#x22;&#x3E;about&#x3C;/a&#x3E;. &#x3C;a href=&#x22;#user-content-fnref-8&#x22; data-footnote-backref aria-label=&#x22;Back to reference 4&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-9&#x22;&#x3E;
&#x3C;p&#x3E;At least that&#x27;s what I can remember from the few emails I sent them back then, I lost the emails they sent &#x3C;em&#x3E;me&#x3C;/em&#x3E;, so I don&#x27;t remember the details. &#x3C;a href=&#x22;#user-content-fnref-9&#x22; data-footnote-backref aria-label=&#x22;Back to reference 5&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-10&#x22;&#x3E;
&#x3C;p&#x3E;Not that I really wanted it to. I always wanted to keep BTD free of charge and free of ads or anything. &#x3C;a href=&#x22;#user-content-fnref-10&#x22; data-footnote-backref aria-label=&#x22;Back to reference 6&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-11&#x22;&#x3E;
&#x3C;p&#x3E;Analytics/telemetry would have been really useful during that time, but I never set that up by pure laziness. &#x3C;a href=&#x22;#user-content-fnref-11&#x22; data-footnote-backref aria-label=&#x22;Back to reference 7&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/bettertweetdeck-post-mortem-part-2&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
        <entry>
          <title>Better TweetDeck, A Post-Mortem, Part 1: frequently asked questions</title>
          <link href="https://damien.zone/bettertweetdeck-post-mortem-part-1-faq" rel="alternate"/>
          <id>https://damien.zone/bettertweetdeck-post-mortem-part-1-faq</id>
          <published>2023-07-12T07:00:00Z</published>
          <updated>2024-09-22T01:42:24Z</updated>
          <author>
            <name>Damien Erambert</name>
          </author>
          <content type="html">
            &#x3C;p&#x3E;Welp, here we are. As I write this, it seems TweetDeck is heading toward the paywall&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-1&#x22; id=&#x22;user-content-fnref-1&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;1&#x3C;/a&#x3E;&#x3C;/sup&#x3E;, so I decided to &#x3C;a href=&#x22;https://better.tw/&#x22;&#x3E;discontinue Better TweetDeck&#x3C;/a&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;If you&#x27;ve been using it, I&#x27;m sure you have many questions on your mind. Some of which I&#x27;ve answered in the past already on my various accounts, but I feel they deserve to be all answered in the same place.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;cant-you-support-the-new-tweetdeck&#x22;&#x3E;Can&#x27;t you support the new TweetDeck?&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Yes and no. I looked into supporting the new TweetDeck back in 2022 and found that the way it was built makes it very hard to build on top of it (more on that later). It&#x27;s not impossible, of course, and maybe someone else would figure it out, but after spending 8 (at this point) years working on Better TweetDeck, I didn&#x27;t want to start from scratch on top of a completely new base.&#x3C;/p&#x3E;
&#x3C;p&#x3E;That&#x27;s also when I started entertaining the idea of making my own 3rd party web client for Twitter (and possibly Mastodon), which I believe could have been interesting. But then Elon Musk acquired Twitter and &#x3C;a href=&#x22;https://www.theverge.com/2023/3/30/23662832/twitter-api-tiers-free-bot-novelty-accounts-basic-enterprice-monthly-price&#x22;&#x3E;jacked up the API pricing&#x3C;/a&#x3E;, which killed that idea in the nub &#x1F62C;&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;but-why-cant-you-support-it&#x22;&#x3E;But &#x3C;em&#x3E;why&#x3C;/em&#x3E; can&#x27;t you support it?&#x3C;/h4&#x3E;
&#x3C;p&#x3E;This part is going to be kind of technical, so buckle up!&#x3C;/p&#x3E;
&#x3C;p&#x3E;If you ever used it, you probably noticed that New TweetDeck looks and feels &#x3C;strong&#x3E;a lot&#x3C;/strong&#x3E; like Twitter Web. It isn&#x27;t a coincidence. That is because, on a technical level, it IS Twitter Web But With Columns.
From Twitter&#x27;s point of view, this is a net positive because it means that features added to Twitter Web are easily ported to TweetDeck.
For Better TweetDeck? Not so much. Like I said above, it would mean throwing everything I wrote and start again, which frankly is kind of depressing to think about.&#x3C;/p&#x3E;
&#x3C;p&#x3E;But even if I had the motivation, this is easier said than done&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-2&#x22; id=&#x22;user-content-fnref-2&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;2&#x3C;/a&#x3E;&#x3C;/sup&#x3E;. Let&#x27;s look at why in details by inspecting their tech stack&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-3&#x22; id=&#x22;user-content-fnref-3&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;3&#x3C;/a&#x3E;&#x3C;/sup&#x3E;:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;&#x3C;a href=&#x22;https://redux.js.org/&#x22;&#x3E;Redux&#x3C;/a&#x3E; is used for state/data management. This is pretty common in big JS apps. Redux&#x27;s state is fairly &#x22;easy&#x22; to look and poke at, but messing with data only gets you so far, unfortunately.&#x3C;/li&#x3E;
&#x3C;li&#x3E;&#x3C;a href=&#x22;https://react.dev/&#x22;&#x3E;React&#x3C;/a&#x3E; (UI framework) in conjunction with &#x3C;a href=&#x22;https://necolas.github.io/react-native-web/&#x22;&#x3E;react-native-web&#x3C;/a&#x3E;&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-4&#x22; id=&#x22;user-content-fnref-4&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;4&#x3C;/a&#x3E;&#x3C;/sup&#x3E; make it very hard to mod anything in a reliable way because the component tree of the app is just a bunch of generic &#x22;views&#x22; that are indistinguishable from each other and they&#x27;re all styled with machine-generated CSS classes that change depending on the underlying styles applied. All of this means that any UI or CSS mod is hard to make and maintain. Some projects like &#x3C;a href=&#x22;https://github.com/insin/control-panel-for-twitter&#x22;&#x3E;Control Panel for Twitter&#x3C;/a&#x3E; do it, but I frankly don&#x27;t have it in me to do that.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;That&#x27;s for the technical side. The obvious elephant in the room is the upcoming paywall behind TweetDeck. When working on Better TweetDeck (or any side-project for that matter) I want to make sure that keeping it around/using it does &#x3C;em&#x3E;not&#x3C;/em&#x3E; cost me money. Having to pay 8$ for Twitter Blue to use TweetDeck goes against that. Even if Elon Musk didn&#x27;t buy Twitter, a lot of people would be reticent in doing that, so I would see Better TweetDeck&#x27;s userbase shrink, which sucks.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;okay-then-what-about-supporting-mastodonthreadsbluesky&#x22;&#x3E;Okay then, what about supporting Mastodon/Threads/Bluesky?&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Oh boy. That one is a doozy so let&#x27;s take it one at a time, shall we?&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;mastodon&#x22;&#x3E;Mastodon&#x3C;/h4&#x3E;
&#x3C;p&#x3E;I&#x27;ve been using Mastodon since April 2017. I shortly contributed to the project&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-5&#x22; id=&#x22;user-content-fnref-5&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;5&#x3C;/a&#x3E;&#x3C;/sup&#x3E; and helped moderate the main &#x3C;a href=&#x22;https://mastodon.social&#x22;&#x3E;mastodon.social&#x3C;/a&#x3E; instance for a short while so I&#x27;m &#x3C;em&#x3E;a bit&#x3C;/em&#x3E; familiar with it. While I like the project and the network despite its issues... the Web interface uses a similar stack as Twitter Web (not exactly the same, mind you), meaning building a &#x22;Better Mastodon&#x22; would also require a lot of work, maintenance AND also juggling with different instances which may or may not run forks/modifications of the software. So this is a no-go.&#x3C;/p&#x3E;
&#x3C;p&#x3E;But maybe I could make my own client? Maybe! This is also a lot of work and I haven&#x27;t had the time/motivation to start such a project. The recent &#x3C;a href=&#x22;https://nolanlawson.com/2023/01/09/retiring-pinafore/&#x22;&#x3E;retirement of Pinafore&#x3C;/a&#x3E; frankly discouraged me. Maintaining Better TweetDeck was already a lot of work, but a whole Mastodon client is something else entirely. Not worth it for me to do it at this time. Besides, the &#x3C;a href=&#x22;https://joinmastodon.org/apps&#x22;&#x3E;app ecosystem&#x3C;/a&#x3E; of Mastodon is going very well and isn&#x27;t going anywhere anytime soon because, unlike Twitter, Mastodon isn&#x27;t headed by a billionaire who wants to make a quick buck on the back of developers&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-6&#x22; id=&#x22;user-content-fnref-6&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;6&#x3C;/a&#x3E;&#x3C;/sup&#x3E;.&#x3C;/p&#x3E;
&#x3C;p&#x3E;So at the time of writing this (July 2023), doing anything substantial with Mastodon is out of the question. I do have a smaller project called &#x3C;a href=&#x22;https://tokimeki-mastodon.vercel.app/&#x22;&#x3E;Tokimeki Mastodon&#x3C;/a&#x3E; which is a clone of &#x3C;a href=&#x22;https://tokimeki-unfollow.glitch.me/&#x22;&#x3E;Tokimeki Unfollow&#x3C;/a&#x3E; which lets you clean up your followings list, in case you&#x27;re interested!&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;bluesky&#x22;&#x3E;Bluesky&#x3C;/h4&#x3E;
&#x3C;p&#x3E;Bluesky is...a lot, and not in a good way &#x1FAE0;. The main web/mobile app is janky, the content moderation situation is &#x3C;a href=&#x22;https://techcrunch.com/2023/06/08/blueskys-growing-pains-strain-relationship-with-its-black-community-moderation/&#x22;&#x3E;embarassingly&#x3C;/a&#x3E; &#x3C;a href=&#x22;https://techcrunch.com/2023/07/17/bluesky-racial-slurs-banned-list-usernames/&#x22;&#x3E;bad&#x3C;/a&#x3E;, &#x3C;a href=&#x22;https://www.wikiwand.com/en/Bluesky_Social&#x22;&#x3E;Jack Dorsey&#x3C;/a&#x3E; is still involved, the leadership has &#x3C;a href=&#x22;https://blueskyweb.xyz/blog/4-13-2023-moderation&#x22;&#x3E;questionable views on moderation&#x3C;/a&#x3E;, it&#x27;s frankly a mess. And it is still invite-only, so you can imagine how well things will be going when they open up/allow anyone to start an instance.&#x3C;/p&#x3E;
&#x3C;p&#x3E;The main web app is very similar to Twitter&#x27;s in its tech stack, meaning that my only reasonable plan forward would be to either &#x3C;a href=&#x22;https://github.com/bluesky-social/social-app&#x22;&#x3E;contribute to the code&#x3C;/a&#x3E; (which I&#x27;m not going to do. The project has millions of dollars in VC funding, I refuse to do free labor for them on principle) or &#x3C;a href=&#x22;https://atproto.com/docs&#x22;&#x3E;build my own web client&#x3C;/a&#x3E;. The latter &#x3C;em&#x3E;would&#x3C;/em&#x3E; be feasible, and others have done it already, but the aforementioned issues are too important for me to entertain the idea of doing anything with Bluesky.&#x3C;/p&#x3E;
&#x3C;h4 id=&#x22;threads&#x22;&#x3E;Threads&#x3C;/h4&#x3E;
&#x3C;p&#x3E;I am uninterested in Threads. Plain and simple. It is an Instagram/Facebook&#x3C;sup&#x3E;&#x3C;a href=&#x22;#user-content-fn-7&#x22; id=&#x22;user-content-fnref-7&#x22; data-footnote-ref aria-describedby=&#x22;footnote-label&#x22;&#x3E;7&#x3C;/a&#x3E;&#x3C;/sup&#x3E; app, meaning it:&#x3C;/p&#x3E;
&#x3C;ul&#x3E;
&#x3C;li&#x3E;&#x3C;a href=&#x22;https://twitter.com/mehedih_/status/1676916689374420993&#x22;&#x3E;will have ads shoved in users&#x27; face&#x3C;/a&#x3E;&#x3C;/li&#x3E;
&#x3C;li&#x3E;doesn&#x27;t have a chronological timeline, and everything Instagram did tells me they won&#x27;t give a crap&#x3C;/li&#x3E;
&#x3C;li&#x3E;doesn&#x27;t have any API to work on top of&#x3C;/li&#x3E;
&#x3C;li&#x3E;doesn&#x27;t have and might never have a Web version&#x3C;/li&#x3E;
&#x3C;li&#x3E;already &#x3C;a href=&#x22;https://mashable.com/article/threads-hate-speech-disinformation&#x22;&#x3E;has a crappy moderation situation&#x3C;/a&#x3E; and likely won&#x27;t improve&#x3C;/li&#x3E;
&#x3C;li&#x3E;is owned by frigging Mark Zuckerberg. Come on! I hate Elon Musk and Jack Dorsey but I am &#x3C;em&#x3E;not&#x3C;/em&#x3E; jumping on Zuckerberg&#x27;s lap either, screw that.&#x3C;/li&#x3E;
&#x3C;/ul&#x3E;
&#x3C;p&#x3E;So anyway, no, I&#x27;m not building a &#x22;ThreadsDeck&#x22;, &#x22;Better Threads&#x22; or anything, screw them.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;is-there-a-future-where-the-project-would-be-revived-elon-leavingtweetdeck-becoming-free-againetc&#x22;&#x3E;Is there a future where the project would be revived? (Elon leaving/TweetDeck becoming free again/etc.)?&#x3C;/h3&#x3E;
&#x3C;p&#x3E;I honestly don&#x27;t know? If Elon were to sell Twitter back and remove itself completely (which I doubt he will because his ego is in the way), or TweetDeck were to become free again...it wouldn&#x27;t bring back the workers that &#x3C;em&#x3E;made&#x3C;/em&#x3E; TweetDeck and allowed (and even encouraged!) Better TweetDeck to exist. Twitter is a shell of its former self and I think at this point it&#x27;s healthier to accept that and let it go, unfortunately.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;how-about-a-better-twitter-extension&#x22;&#x3E;How about a &#x22;Better Twitter&#x22; extension?&#x3C;/h3&#x3E;
&#x3C;p&#x3E;I have little interest in doing that, and to be honest &#x3C;a href=&#x22;https://github.com/insin/control-panel-for-twitter&#x22;&#x3E;Control Panel for Twitter&#x3C;/a&#x3E; is already doing an amazing job in that department. I don&#x27;t think I could do it better.&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;any-other-projects-youre-currently-working-on&#x22;&#x3E;Any other projects you&#x2019;re currently working on?&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Not really. As I&#x27;m writing this, my biggest project is finishing &#x3C;a href=&#x22;https://www.zelda.com/tears-of-the-kingdom/&#x22;&#x3E;Tears of the Kingdom&#x3C;/a&#x3E; &#x1F604;&#x3C;/p&#x3E;
&#x3C;h3 id=&#x22;i-wanna-donate-to-thank-you-can-i-do-that&#x22;&#x3E;I wanna donate to thank you, can I do that?&#x3C;/h3&#x3E;
&#x3C;p&#x3E;Sure! That said... I&#x27;d rather you keep your money and give it to a friend in need, or a charity. I have a day job that pays well, I&#x27;m fine. That said if you really really want to do it, I have a &#x3C;a href=&#x22;https://paypal.me/Eramdam&#x22;&#x3E;Paypal&#x3C;/a&#x3E; you can donate to.&#x3C;/p&#x3E;
&#x3C;h2 id=&#x22;conclusion&#x22;&#x3E;Conclusion&#x3C;/h2&#x3E;
&#x3C;p&#x3E;That&#x27;s it! Thanks for reading, and see you later for the next part which will try to through Better TweetDeck&#x27;s history and shout out the work of the folks that made the project special &#x1F604;&#x3C;/p&#x3E;
&#x3C;section data-footnotes class=&#x22;footnotes&#x22;&#x3E;&#x3C;h2 class=&#x22;sr-only&#x22; id=&#x22;footnote-label&#x22;&#x3E;Footnotes&#x3C;/h2&#x3E;
&#x3C;ol&#x3E;
&#x3C;li id=&#x22;user-content-fn-1&#x22;&#x3E;
&#x3C;p&#x3E;Who knows, by the time this post gets published, Twitter will reverse &#x3C;a href=&#x22;https://twitter.com/Support/status/1675990712297443330&#x22;&#x3E;their decision&#x3C;/a&#x3E; because what happens there doesn&#x27;t seem to make sense anymore. &#x3C;a href=&#x22;#user-content-fnref-1&#x22; data-footnote-backref aria-label=&#x22;Back to reference 1&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-2&#x22;&#x3E;
&#x3C;p&#x3E;I&#x27;m sure someone, somewhere, will figure this out eventually but I frankly didn&#x27;t have the will nor the energy to do it. The whole &#x22;management situation&#x22; at Twitter, in addition to the impending paywall killed the remains of motivation I had &#x1F605; &#x3C;a href=&#x22;#user-content-fnref-2&#x22; data-footnote-backref aria-label=&#x22;Back to reference 2&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-3&#x22;&#x3E;
&#x3C;p&#x3E;I&#x27;m not revealing some grand secrets or anything, all of this can be figured out by opening the DevTools in your favorite browser and knowing where to look. &#x3C;a href=&#x22;#user-content-fnref-3&#x22; data-footnote-backref aria-label=&#x22;Back to reference 3&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-4&#x22;&#x3E;
&#x3C;p&#x3E;You may have heard of &#x22;React Native&#x22; as a thing that lets people write apps for iOS &#x3C;em&#x3E;and&#x3C;/em&#x3E; Android with the same codebase. &#x3C;code&#x3E;react-native-web&#x3C;/code&#x3E; allows to share code between an iOS/Android React Native app and its Web counterpart (it does a bit more but i&#x27;m simplifying here). &#x3C;a href=&#x22;#user-content-fnref-4&#x22; data-footnote-backref aria-label=&#x22;Back to reference 4&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-5&#x22;&#x3E;
&#x3C;p&#x3E;Mostly in the form of French localization strings and very very tiny features. &#x3C;a href=&#x22;#user-content-fnref-5&#x22; data-footnote-backref aria-label=&#x22;Back to reference 5&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-6&#x22;&#x3E;
&#x3C;p&#x3E;Please, &#x3C;a href=&#x22;https://en.wikipedia.org/wiki/Eugen_Rochko&#x22;&#x3E;Eugen&#x3C;/a&#x3E;, don&#x27;t make me regret saying this lol. &#x3C;a href=&#x22;#user-content-fnref-6&#x22; data-footnote-backref aria-label=&#x22;Back to reference 6&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;li id=&#x22;user-content-fn-7&#x22;&#x3E;
&#x3C;p&#x3E;I am not calling them Meta. Fuck this metaverse bullshit. &#x3C;a href=&#x22;#user-content-fnref-7&#x22; data-footnote-backref aria-label=&#x22;Back to reference 7&#x22; class=&#x22;data-footnote-backref&#x22;&#x3E;&#x21A9;&#x3C;/a&#x3E;&#x3C;/p&#x3E;
&#x3C;/li&#x3E;
&#x3C;/ol&#x3E;
&#x3C;/section&#x3E;
            &#x3C;a href=&#x22;https://damien.zone/bettertweetdeck-post-mortem-part-1-faq&#x22;&#x3E;Permalink / Comments&#x3C;/a&#x3E;
          </content>
        </entry>
        
  </feed>